it-swarm-pt.tech

usando template externo (C ++ 11)

Figura 1: modelos de função

TemplHeader.h

template<typename T>
void f();

TemplCpp.cpp

template<typename T>
void f(){
   //...
}    
//explicit instantation
template void f<T>();

Main.cpp

#include "TemplHeader.h"
extern template void f<T>(); //is this correct?
int main() {
    f<char>();
    return 0;
}

Esta é a maneira correta de usar extern template, ou eu uso essa palavra-chave apenas para modelos de classe como na Figura 2?

Figura 2: modelos de classes

TemplHeader.h

template<typename T>
class foo {
    T f();
};

TemplCpp.cpp

template<typename T>
void foo<T>::f() {
    //...
}
//explicit instantation
template class foo<int>;

Main.cpp

#include "TemplHeader.h"
extern template class foo<int>();
int main() {
    foo<int> test;
    return 0;
}

Eu sei que é bom colocar tudo isso em um arquivo de cabeçalho, mas se instanciamos modelos com os mesmos parâmetros em vários arquivos, então temos várias definições iguais e o compilador removerá todas elas (exceto uma) para evitar erros. Como eu uso extern template? Podemos usá-lo apenas para classes, ou podemos usá-lo para funções também?

Além disso, a Figura 1 e a Figura 2 podem ser expandidas para uma solução na qual os modelos estão em um único arquivo de cabeçalho. Nesse caso, precisamos usar a palavra-chave extern template para evitar várias instâncias iguais. Isso é apenas para classes ou funções também?

97
codekiddy

Você só deve usar extern template para forçar o compilador a não instanciar um template quando você sabe que será instanciado em outro lugar. Ele é usado para reduzir o tempo de compilação e o tamanho do arquivo de objeto.

Por exemplo:

// header.h

template<typename T>
void ReallyBigFunction()
{
    // Body
}

// source1.cpp

#include "header.h"
void something1()
{
    ReallyBigFunction<int>();
}

// source2.cpp

#include "header.h"
void something2()
{
    ReallyBigFunction<int>();
}

Isso resultará nos seguintes arquivos de objeto:

source1.o
    void something1()
    void ReallyBigFunction<int>()    // Compiled first time

source2.o
    void something2()
    void ReallyBigFunction<int>()    // Compiled second time

Se ambos os arquivos estiverem vinculados, um void ReallyBigFunction<int>() será descartado, resultando em perda de tempo de compilação e tamanho do arquivo de objeto.

Para não desperdiçar tempo de compilação e tamanho de arquivo de objeto, existe uma palavra-chave extern que faz com que o compilador não compile uma função de template. Você deve usar isto se e somente se você souber ele é usado no mesmo binário em algum outro lugar.

Alterando source2.cpp para:

// source2.cpp

#include "header.h"
extern template void ReallyBigFunction<int>();
void something2()
{
    ReallyBigFunction<int>();
}

Resultará nos seguintes arquivos de objeto:

source1.o
    void something1()
    void ReallyBigFunction<int>() // compiled just one time

source2.o
    void something2()
    // No ReallyBigFunction<int> here because of the extern

Quando ambos estiverem vinculados, o segundo arquivo de objeto usará apenas o símbolo do primeiro arquivo de objeto. Não há necessidade de descarte nem desperdício de tempo de compilação nem tamanho de arquivo de objeto.

Isso deve ser usado apenas dentro de um projeto, como em momentos em que você usa um modelo como vector<int> várias vezes, você deve usar extern em todos os arquivos, exceto um.

Isso também se aplica a classes e função como uma e até mesmo funções de membro de modelo.

158
Dani

Wikipedia tem o melhor descrição

Em C++ 03, o compilador deve instanciar um modelo sempre que um modelo totalmente especificado for encontrado em uma unidade de tradução. Se o modelo for instanciado com os mesmos tipos em muitas unidades de tradução, isso pode aumentar drasticamente os tempos de compilação. Não há como evitar isso em C++ 03, portanto, o C++ 11 introduziu declarações externas de modelo, análogas às declarações de dados externas.

O C++ 03 possui esta sintaxe para obrigar o compilador a instanciar um template:

  template class std::vector<MyClass>;

O C++ 11 agora fornece esta sintaxe:

  extern template class std::vector<MyClass>;

que diz ao compilador para não instanciar o modelo nesta unidade de tradução.

O aviso: nonstandard extension used...

O Microsoft VC++ costumava ter uma versão não padrão desse recurso já há alguns anos (em C++ 03). O compilador avisa sobre isso para evitar problemas de portabilidade com o código que precisava compilar em diferentes compiladores também.

Veja a amostra na página vinculada para ver se funciona da mesma maneira. Você pode esperar que a mensagem desapareça com versões futuras do MSVC, exceto, é claro, ao usar outras extensões de compilador não-padrão ao mesmo tempo.

42
sehe

O problema conhecido com os modelos é o inchaço de código, que é conseqüência da geração da definição de classe em cada módulo que invoca a especialização de modelo de classe. Para evitar isso, começando com C++ 0x, pode-se usar a palavra-chave extern na frente da especialização do modelo de classe

#include <MyClass> extern template class CMyClass<int>;

A instância explícita da classe template deve acontecer apenas em uma única unidade de tradução, preferivelmente aquela com definição de template (MyClass.cpp)

template class CMyClass<int>;
template class CMyClass<float>;
4
damirlj

Se você usou externamente para funções antes, exatamente a mesma filosofia é seguida para modelos. se não, ir embora externamente para funções simples pode ajudar. Além disso, você pode colocar o (s) extern (s) no arquivo de cabeçalho e incluir o cabeçalho quando precisar dele.

0
qqqqq