Compilador não criar ostream templated << operador
-
23-08-2019 - |
Pergunta
Eu tenho uma classe, definida em uma cabeça como:
template <typename T> class MyClass
{
template <typename U> friend std::ostream& operator<<(std::ostream& output, const MyClass<U>& p);
public:
...
}
Em um arquivo de implementação, eu tenho:
template <typename U> std::ostream& operator<<(std::ostream& output, const MyClass<U>& m)
{
output << "Some stuff";
return output;
}
Que todos os olhares bastante kosher. No entanto, quando tento usar esse operador (ou seja, std :: cout << MyClass ()), eu recebo o seguinte erro vinculador:
Undefined symbols: std::basic_ostream<char, std::char_traits<char> >& operator<< <InnerType>(std::basic_ostream<char, std::char_traits<char> >&, MyClass<InnerType> const&)
Estou surpreso o compilador não automagicially gerado isso para mim ... Qualquer sugestões sobre o que estou fazendo de errado?
Solução
Em um arquivo de implementação, eu tenho:
Esse é o problema. Você não pode dividir definições de modelo entre arquivos de cabeçalho e implementação. Devido à natureza de modelos, compiladores C ++ são mimado aqui. Defina todo o código no cabeçalho para fazer o trabalho.
Na verdade, o problema aqui é que todas as definições de modelo deve residir na mesma unidade de compilação porque o C ++ padrão não define como informações do modelo são compartilhados entre diferentes unidades. Estas unidades são costuradas pelo vinculador, mas os genéricos são resolvidos em tempo de compilação (que é mais cedo), não em tempo de ligação.
Teoricamente, o C ++ padrão define uma palavra-chave, export
, para lidar com esses casos. Na prática, não implementos compilador isso (com uma exceção?), E não há nenhuma intenção de mudar isso porque o custo / utilidade trade-off não é considerado bom o suficiente.
Outras dicas
demasiado muitos modelos - isso funciona:
#include <iostream>
using namespace std;
template <typename T> struct MyClass {
friend ostream & operator << ( ostream & os, MyClass<T> & c ) {
os << "MyClass\n";
return os;
}
};
int main() {
MyClass <int> c;
cout << c;
}