重载friend operator <<用于模板类

sta*_*orn 56 c++ templates operator-overloading friend ostream

我现在已经在StackOverflow.com上阅读了几个关于我的问题的问题,但似乎没有一个能解决我的问题.或者我可能做错了... <<如果我将其转换为内联函数,则重载会起作用.但是我如何让它在我的情况下工作?

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;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*eas 147

这是常见问题中的一个,这些问题具有相似但不完全相同的不同方法.这三种方法的不同之处在于您宣布成为您职能的朋友 - 然后是您如何实施它.

外向的

将模板的所有实例化声明为朋友.这是你已经接受的答案,也是大多数其他答案的建议.在这种方法中,您D<T>通过声明朋友的所有operator<<实例来不必要地打开您的特定实例.也就是说,std::ostream& operator<<( std::ostream &, const D<int>& )可以访问所有的内部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
}
Run Code Online (Sandbox Code Playgroud)

内向的人

仅将插入运算符的特定实例声明为朋友.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>
   }
};
Run Code Online (Sandbox Code Playgroud)

在第一个版本中,您不是为模板operator<<的每个实例化创建模板化的,而是非模板化的函数Test.同样,差异是微妙的,但这基本上等同于手动添加:std::ostream& operator<<( std::ostream&, const Test<int>& )实例化时Test<int>,以及实例化时Test使用double或使用任何其他类型时的另一个类似重载.

第三个版本更麻烦.如果没有内联代码,并且使用模板,您可以将模板的单个实例化声明为您的类的朋友,而无需打开所有其他实例:

// 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> ...
}
Run Code Online (Sandbox Code Playgroud)

利用外向的人

第三个选项与第一个选项之间的细微差别在于您对其他课程的开放程度.外向版本中滥用的一个例子是想要访问你的内部的人,并且这样做:

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...
   }
}
Run Code Online (Sandbox Code Playgroud)


Nim*_*Nim 15

您无法声明这样的朋友,您需要为其指定不同的模板类型.

template <typename SclassT>
friend ostream& operator<< (ostream & os, const D<SclassT>& rhs);
Run Code Online (Sandbox Code Playgroud)

注意SclassT这样它就不会出现阴影classT.定义时

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

  • 请注意,这不是声明`operator <<`作为朋友的特定实例,而是**所有**实例,包括模板的任何特化.请参阅答案[此处](http://stackoverflow.com/questions/4660123/overloading-friend-operator-for-template-class/4661372#4661372) (4认同)