programming - using function template in c++




Armazenando definições de função de modelo C++ em um arquivo.CPP (8)

Eu tenho algum código de modelo que eu preferiria ter armazenado em um arquivo CPP em vez de inline no cabeçalho. Eu sei que isso pode ser feito desde que você saiba quais tipos de modelo serão usados. Por exemplo:

arquivo .h

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

arquivo .cpp

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

Observe as duas últimas linhas - a função foo :: do template é usada apenas com ints e std :: strings, então essas definições significam que o aplicativo irá linkar.

Minha pergunta é - isso é um truque desagradável ou isso funcionará com outros compiladores / linkers? Eu estou usando apenas este código com VS2008 no momento, mas estará querendo portar para outros ambientes.


Essa é uma maneira padrão de definir funções de modelo. Eu acho que existem três métodos que eu li para definir modelos. Ou provavelmente 4. Cada um com prós e contras.

  1. Defina na definição de classe. Eu não gosto disso porque acho que as definições de classe são estritamente para referência e devem ser fáceis de ler. No entanto, é muito menos complicado definir modelos na classe do que fora. E nem todas as declarações de modelo estão no mesmo nível de complexidade. Esse método também torna o modelo um modelo verdadeiro.

  2. Defina o modelo no mesmo cabeçalho, mas fora da classe. Este é o meu caminho preferido na maioria das vezes. Ele mantém sua definição de classe organizada, o modelo permanece um modelo verdadeiro. No entanto, requer nomeação completa de modelos, o que pode ser complicado. Além disso, seu código está disponível para todos. Mas se você precisar que seu código esteja em linha, esta é a única maneira. Você também pode fazer isso criando um arquivo .INL no final das definições de classe.

  3. Inclua o header.h e implementation.CPP no seu main.CPP. Eu acho que é assim que é feito. Você não terá que preparar nenhuma pré-instanciação, ela se comportará como um modelo verdadeiro. O problema que tenho com isso é que não é natural. Normalmente, não incluímos e esperamos incluir arquivos de origem. Eu acho que desde que você incluiu o arquivo de origem, as funções do modelo podem ser embutidas.

  4. Este último método, que foi postado, é definir os modelos em um arquivo de origem, assim como o número 3; mas em vez de incluir o arquivo de origem, pré-instanciamos os modelos para os que precisaremos. Eu não tenho nenhum problema com este método e vem a calhar às vezes. Nós temos um grande código, ele não pode se beneficiar de ser embutido, basta colocá-lo em um arquivo CPP. E se soubermos instanciações comuns e pudermos defini-las. Isso nos impede de escrever basicamente a mesma coisa 5, 10 vezes. Este método tem a vantagem de manter nosso código proprietário. Mas eu não recomendo colocar pequenas funções regularmente usadas em arquivos CPP. Como isso irá reduzir o desempenho da sua biblioteca.

Note, eu não estou ciente das conseqüências de um arquivo obj inchado.


Este código é bem formado. Você só precisa prestar atenção que a definição do modelo é visível no momento da instanciação. Para citar o padrão, § 14.7.2.4:

A definição de um modelo de função não exportado, um modelo de função de membro não exportado ou uma função de membro não exportada ou um membro de dados estático de um modelo de classe deve estar presente em cada unidade de conversão na qual ela é explicitamente instanciada.


Existe, no padrão mais recente, uma palavra-chave ( export ) que ajudaria a aliviar esse problema, mas não é implementada em nenhum compilador que eu conheça, além do Comeau.

Veja o FAQ-lite sobre isso.


Hora de uma atualização! Crie um arquivo embutido (.inl ou provavelmente qualquer outro) e simplesmente copie todas as suas definições nele. Certifique-se de adicionar o modelo acima de cada função ( template <typename T, ...> ). Agora, em vez de incluir o arquivo de cabeçalho no arquivo in-line, você faz o oposto. Inclua o arquivo embutido após a declaração da sua classe ( #include "file.inl" ).

Eu realmente não sei porque ninguém mencionou isso. Não vejo inconvenientes imediatos.


Não há nada de errado com o exemplo que você deu. Mas devo dizer que acredito que não é eficiente armazenar as definições de função em um arquivo cpp. Eu só entendo a necessidade de separar a declaração e definição da função.

Quando usado em conjunto com a instanciação explícita de classes, o BCCL (Boost Concept Check Library) pode ajudá-lo a gerar código de função de modelo em arquivos cpp.


O problema que você descreve pode ser resolvido definindo o modelo no cabeçalho ou através da abordagem descrita acima.

Eu recomendo ler os seguintes pontos do C ++ FAQ Lite :

Eles entram em muitos detalhes sobre esses (e outros) problemas de modelo.


Seu exemplo está correto, mas não é muito portátil. Há também uma sintaxe ligeiramente mais limpa que pode ser usada (como apontado por @ namespace-sid).

Suponha que a classe modelo faça parte de alguma biblioteca que deve ser compartilhada. Outras versões da classe modelo devem ser compiladas? O mantenedor da biblioteca deve antecipar todos os possíveis usos modelados da classe?

Uma abordagem alternativa é uma pequena variação do que você tem: adicionar um terceiro arquivo que é o arquivo de implementação / instanciação do modelo.

arquivo foo.h

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

arquivo foo.cpp

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

arquivo foo-impl.cpp

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

A única ressalva é que você precisa dizer ao compilador para compilar o foo-impl.cpp vez de foo.cpp pois a compilação não faz nada.

Claro, você pode ter várias implementações no terceiro arquivo ou ter vários arquivos de implementação para cada tipo que você gostaria de usar.

Isso permite muito mais flexibilidade ao compartilhar a classe de modelos para outros usos.

Essa configuração também reduz os tempos de compilação para classes reutilizadas porque você não está recompilando o mesmo arquivo de cabeçalho em cada unidade de tradução.


Sim, essa é a maneira padrão de fazer instanciação explícita de especialização . Como você afirmou, não é possível instanciar este modelo com outros tipos.

Editar: corrigido com base no comentário.







templates