为模板类重载friend operator <<

我已经阅读了几个有关我的问题在stackoverflow现在,似乎没有解决我的问题。 或者我也许做错了…重载的<<如果我把它变成一个内联函数。 但是我怎么让它在我的情况下工作?

warning: friend declaration std::ostream& operator<<(std::ostream&, const D<classT>&)' declares a non-template function

warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning

/tmp/cc6VTWdv.o:uppgift4.cc:(.text+0x180): undefined reference to operator<<(std::basic_ostream<char, std::char_traits<char> >&, D<int> const&)' collect2: ld returned 1 exit status

 template <class T> T my_max(T a, T b) { if(a > b) return a; else return b; } template <class classT> class D { public: D(classT in) : d(in) {}; bool operator>(const D& rhs) const; classT operator=(const D<classT>& rhs); friend ostream& operator<< (ostream & os, const D<classT>& rhs); private: classT d; }; int main() { int i1 = 1; int i2 = 2; D<int> d1(i1); D<int> d2(i2); cout << my_max(d1,d2) << endl; return 0; } template <class classT> ostream& operator<<(ostream &os, const D<classT>& rhs) { os << rhs.d; return os; } 

这是那些经常被问到的问题,有不同的方法是相似的,但不是真的一样。 这三种方法在你声称是你的function的朋友 – 然后是你如何实现它的不同。

外向

声明模板的所有实例作为朋友。 这就是你已经接受的答案,也是大多数其他答案提出的。 在这种方法中,通过向朋友声明所有operator<<实例化,不必要地打开特定的实例化D<T> 。 也就是说, std::ostream& operator<<( std::ostream &, const D<int>& )可以访问D<double>所有内部D<double>

 template <typename T> class Test { template <typename U> // all instantiations of this template are my friends friend std::ostream& operator<<( std::ostream&, const Test<U>& ); }; template <typename T> std::ostream& operator<<( std::ostream& o, const Test<T>& ) { // Can access all Test<int>, Test<double>... regardless of what T is } 

内向的人

只能将插入操作符的特定实例声明为朋友。 D<int>在应用于自身时可能喜欢插入运算符,但不希望与std::ostream& operator<<( std::ostream&, const D<double>& )

这可以通过两种方式完成,简单的方法就像@Emery Berger提出的那样,内联运营商 – 由于其他原因,这也是一个好主意:

 template <typename T> class Test { friend std::ostream& operator<<( std::ostream& o, const Test& t ) { // can access the enclosing Test. If T is int, it cannot access Test<double> } }; 

在第一个版本中,您不是创build模板化的operator<< ,而是为每个Test模板的实例化创build一个非模板化的函数。 再一次,差别是微妙的,但这基本上相当于手动添加:当您实例化Test<int>std::ostream& operator<<( std::ostream&, const Test<int>& ) ,而实例化时另一个类似的重载用double Test ,或用任何其他typestesting。

第三个版本比较麻烦。 如果不内联代码,并且使用模板,则可以将该模板的一个实例声明为类的一个朋友,而无需打开所有其他实例:

 // Forward declare both templates: template <typename T> class Test; template <typename T> std::ostream& operator<<( std::ostream&, const Test<T>& ); // Declare the actual templates: template <typename T> class Test { friend std::ostream& operator<< <T>( std::ostream&, const Test<T>& ); }; // Implement the operator template <typename T> std::ostream& operator<<( std::ostream& o, const Test<T>& t ) { // Can only access Test<T> for the same T as is instantiating, that is: // if T is int, this template cannot access Test<double>, Test<char> ... } 

利用外向

第三个选项和第一个选项之间的细微差别在于你打开了多less其他类。 外向版本中滥用的一个例子是有人想要访问你的内部,并做到这一点:

 namespace hacker { struct unique {}; // Create a new unique type to avoid breaking ODR template <> std::ostream& operator<< <unique>( std::ostream&, const Test<unique>& ) { // if Test<T> is an extrovert, I can access and modify *any* Test<T>!!! // if Test<T> is an introvert, then I can only mess up with Test<unique> // which is just not so much fun... } } 

你不能像这样声明一个朋友,你需要为它指定一个不同的模板types。

 template <typename SclassT> friend ostream& operator<< (ostream & os, const D<SclassT>& rhs); 

注意SclassT这样它就不会影响classT 。 定义时

 template <typename SclassT> ostream& operator<< (ostream & os, const D<SclassT>& rhs) { // body.. } 

这对我没有任何编译器警告。

 #include <iostream> using namespace std; template <class T> T my_max(T a, T b) { if(a > b) return a; else return b; } template <class classT> class D { public: D(classT in) : d(in) {}; bool operator>(const D& rhs) const { return (d > rhs.d); } classT operator=(const D<classT>& rhs); friend ostream& operator<< (ostream & os, const D& rhs) { os << rhs.d; return os; } private: classT d; }; int main() { int i1 = 1; int i2 = 2; D<int> d1(i1); D<int> d2(i2); cout << my_max(d1,d2) << endl; return 0; } 

干得好:

 #include <cstdlib> #include <iostream> using namespace std; template <class T> T my_max(T a, T b) { if(a > b) return a; else return b; } template <class classT> class D { public: D(classT in) : d(in) {}; bool operator>(const D& rhs) const { return d > rhs.d;}; classT operator=(const D<classT>& rhs); template<class classT> friend ostream& operator<< (ostream & os, const D<classT>& rhs); private: classT d; }; template<class classT> ostream& operator<<(ostream& os, class D<typename classT> const& rhs) { os << rhs.d; return os; } int main() { int i1 = 1; int i2 = 2; D<int> d1(i1); D<int> d2(i2); cout << my_max(d1,d2) << endl; return 0; } 

我认为你不应该把朋友放在第一位。

你可以创build一个公共方法调用打印,像这样(对于非模板类):

 std::ostream& MyClass::print(std::ostream& os) const { os << "Private One" << privateOne_ << endl; os << "Private Two" << privateTwo_ << endl; os.flush(); return os; } 

然后,在课外(但在同一个命名空间)

 std::ostream& operator<<(std::ostream& os, const MyClass& myClass) { return myClass.print(os); } 

我认为它也适用于模板类,但我还没有testing。