我有一个类,在头部定义为:
template <typename T> class MyClass
{
template <typename U> friend std::ostream& operator<<(std::ostream& output, const MyClass<U>& p);
public:
...
}
在实施文件中,我有:
template <typename U> std::ostream& operator<<(std::ostream& output, const MyClass<U>& m)
{
output << "Some stuff";
return output;
}
这一切看起来都相当犹太。但是,当我尝试使用此运算符(即std :: cout&lt;&lt;&lt; MyClass())时,我收到以下链接器错误:
Undefined symbols: std::basic_ostream<char, std::char_traits<char> >& operator<< <InnerType>(std::basic_ostream<char, std::char_traits<char> >&, MyClass<InnerType> const&)
我很惊讶编译器没有为我自动生成这个...对于我做错了什么建议?
答案 0 :(得分:8)
在实施文件中,我有:
这就是问题所在。您无法在标头和实现文件之间拆分模板定义。由于模板的性质,C ++编译器在这里很挑剔。定义标题中的所有代码以使其有效。
实际上,这里的问题是所有模板定义必须位于同一个编译单元中,因为C ++标准没有定义如何在不同单元之间共享模板信息。这些单元由链接器拼接在一起,但泛型在编译时(早先)解析, not 在链接时解析。
理论上,C ++标准定义了一个关键字export
来处理这些情况。在实践中,没有编译器实现了这个(有一个例外?),并且无意改变它,因为成本/实用性权衡不够好。
答案 1 :(得分:1)
模板太多 - 这有效:
#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;
}