为模板类重载友元运算符 <<

Posted

技术标签:

【中文标题】为模板类重载友元运算符 <<【英文标题】:Overloading friend operator << for template class 【发布时间】:2010-11-20 19:43:34 【问题描述】:

我正在尝试将运算符

friend declaration std::ostream& operator<<(ostream& out, Pair<T,U>& v) declares a non template function

对于此代码:

friend ostream& operator<<(ostream&, Pair<T,U>&);

它给出了第二个警告作为建议

if this is not what you intended, make sure the function template has already been declared and add <> after the function name here

这是函数定义

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v)

    out << v.val1 << " " << v.val2;

这是整个班级。

template <class T, class U>
class Pair
public:
    Pair(T v1, U v2) : val1(v1), val2(v2)
    ~Pair()
    Pair& operator=(const Pair&);
    friend ostream& operator<<(ostream&, Pair<T,U>&);

private:
    T val1;
    U val2;
;

我不确定要从推荐警告中得出什么结论,除此之外,我可能必须在朋友声明中添加一些内容。有谁知道这个的正确语法?谢谢。

【问题讨论】:

【参考方案1】:

简单的内联版本:

template<typename T> class HasFriend 
    private:
        T item;
    public:
       ~HasFriend() 
       HasFriend(const T &i) : item(i) 
    friend ostream& operator<<(ostream& os, const HasFriend<T>& x) 
        return os << "s(" << sizeof(x) << ").op<<" << x.item << endl;
    
;

修改后的模板版本:

template<template<typename /**/> class U, typename V>
ostream& operator<<(ostream &os, const U<V> &x) 
    return os << "s(" << sizeof(x) << ").op<<" << x.item << endl;


template<typename T> class HasFriend 
    private:
        T item;
    public:
       ~HasFriend() 
       HasFriend(const T &i) : item(i) 
    friend ostream& operator<<<>(ostream&, const HasFriend<T>&);
;

【讨论】:

【参考方案2】:

你将operator

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v)

    return out << v.val1 << " " << v.val2;

除此之外,我在 Visual Studio 2008 下编译您的代码并在第 4 级警告时没有任何问题或警告。哦,有经典的链接器错误,但是通过将模板函数定义移动到类声明很容易绕过,如C++ FAQ 中所述。

我的测试代码:

#include <iostream>
using namespace std;

template <class T, class U>
class Pair 
public:
    Pair(T v1, U v2) : val1(v1), val2(v2)
    ~Pair()
    Pair& operator=(const Pair&);
    friend ostream& operator<<(ostream& out, Pair<T,U>& v)
    
        return out << v.val1 << " " << v.val2;
    
private:    
    T val1;
    U val2;
;

int main() 
    Pair<int, int> a(3, 4);
    cout << a;      

【讨论】:

【参考方案3】:

您希望将该模板的一个实例(一般称为“专业化”)成为朋友。你可以按照以下方式进行

template <class T, class U>
class Pair
public:
    Pair(T v1, U v2) : val1(v1), val2(v2)
    ~Pair()
    Pair& operator=(const Pair&);
    friend ostream& operator<< <> (ostream&, Pair<T,U>&);

private:
    T val1;
    U val2;
;

因为编译器从参数列表中知道模板参数是TU,所以您不必将它们放在&lt;...&gt; 之间,因此可以将它们留空。请注意,您必须在 Pair 模板上方声明 operator&lt;&lt;,如下所示:

template <class T, class U> class Pair;

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v);

// now the Pair template definition...

【讨论】:

+1 这实际上是编译器所抱怨的。另一个答案通过解决方法解决了这个问题:它不是告诉编译器朋友是模板的特化,而是为给定类型创建一个非模板操作符 我同意大卫的观点;这是最佳实践和良好编程方面的最佳解决方案。 哇,多余的&lt;&gt;很容易错过!

以上是关于为模板类重载友元运算符 <<的主要内容,如果未能解决你的问题,请参考以下文章

什么运算符一定要重载友元函数,什么时候一定要重载为成员函数?

操作符(运算符)重载注意事项(含模板类中<<;;重载)

C++:使用类|| 运算符重载友元

运算符重载

关于友元函数,运算符重载和类的类型转换

为什么operator<<;;运算符重载一定要为友元函数呢?