编译器没有创建模板化的ostream <<运算符

use*_*167 3 c++ templates operator-overloading ostream operator-keyword

我有一个类,在头部定义为:

template <typename T> class MyClass
{
   template <typename U> friend std::ostream& operator<<(std::ostream& output, const MyClass<U>& p);
   public:
      ...
}
Run Code Online (Sandbox Code Playgroud)

在实现文件中,我有:

template <typename U> std::ostream& operator<<(std::ostream& output, const MyClass<U>& m)
{
   output << "Some stuff";
   return output;
}
Run Code Online (Sandbox Code Playgroud)

这一切看起来都相当犹豫.但是,当我尝试使用此运算符(即std :: cout << MyClass())时,我收到以下链接器错误:

Undefined symbols: std::basic_ostream<char, std::char_traits<char> >& operator<< <InnerType>(std::basic_ostream<char, std::char_traits<char> >&, MyClass<InnerType> const&)
Run Code Online (Sandbox Code Playgroud)

我很惊讶编译器没有为我自动生成这个...有什么建议我做错了什么?

Kon*_*lph 8

在实现文件中,我有:

那就是问题所在.您无法在标头和实现文件之间拆分模板定义.由于模板的性质,C++编译器在这里很挑剔.定义标题中的所有代码以使其工作.

实际上,这里的问题是所有模板定义必须位于同一个编译单元中,因为C++标准没有定义如何在不同单元之间共享模板信息.这些单元由链接器拼接在一起,但泛型在编译时(早期)解析,而不是在链接时解析.

从理论上讲,C++标准定义了一个关键字export来处理这些情况.在实践中,没有编译器实现这一点(有一个例外吗?),并且无意改变它,因为成本/实用性权衡被认为不够好.