重载朋友运算符<为模板类 [英] overloading friend operator<< for template class

查看:116
本文介绍了重载朋友运算符<为模板类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经读了几个关于我的问题stackoverflow的问题,现在,没有一个似乎解决我的问题。或者我可能做错了...
重载的<< 如果我把它变成一个内联函数。



警告:朋友声明std :: ostream& <<<<<<(std :: ostream& amp; const D< classT>&)'声明一个非模板函数



warning:(如果这不是你想要的,请确保函数模板已经被声明,并在这里的函数名后添加<>)-Wno-non-template-friend禁用此警告



/tmp/cc6VTWdv.o:uppgift4.cc :(。text + 0x180):未定义的对操作符的引用< (std :: basic_ostream< char,std :: char_traits< char>&);
collect2:ld返回1退出状态

 模板< 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&运算符<< (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;
}


解决方案

问题有不同的方法是相似的,但不是真的相同。



外向



将模板的所有实例化为朋友。这是你接受的答案,也是大多数其他答案建议。在这种方法中,通过声明朋友all 运算符<< 实例化,不必要地打开你的特定实例化 D 也就是说, std :: ostream& <<<<(std :: ostream& const D< int>&)

  template< typename T> 
class Test {
template< typename U> //这个模板的所有实例化都是我的朋友
friend std :: ostream& operator<<(std :: ostream& const test< U>&
};
template< typename T>
std :: ostream& <<<<<<<<<<<(std :: ostream& o,const Test< T>){
//可以访问所有Test< int>,Test< double& b}

内向者



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



简单的方式就像@Emery Berger提出的,它是内联操作符 - 这也是一个好主意的其他原因:

  template< typename T> 
class Test {
friend std :: ostream& operator<<<(std :: ostream& o,const Test& t){
//可以访问封闭测试。如果T是int,它不能访问Test< double>
}
};

在此第一个版本中,您不是 $ c> operator ,而是 Test 模板的每个实例化的非模板化函数。再次,差别是微妙的,但这基本上等同于手动添加: std :: ostream&当你实例化 Test< int> 时,操作符<<(std :: ostream& const Test< int>&)当您使用 double 或任何其他类型实例化 Test 时重载



第三个版本比较麻烦。没有内联代码,使用模板,你可以声明模板的一个实例化你的类的朋友,而不打开自己所有其他实例化:

  //向前声明两个模板:
template< typename T>类测试;
template< typename T> std :: ostream&运算符<<(std :: ostream& const test< T>&

//声明实际的模板:
template< typename T>
class Test {
friend std :: ostream&运算符<< < T>(std :: ostream& amp; const Test< T>
};
//实现运算符
template< typename T>
std :: ostream& <<<<(std :: ostream& o,const Test< T& t){
//只能访问Test< T>对于与实例化相同的T,即:
//如果T是int,则该模板不能访问Test< double>,Test< char> ...
}

利用外向 / p>

第三个选项和第一个选项之间的细微差别在于你打开其他类的程度。在外部版本中的滥用示例是希望访问您的内部版本的人员,并执行此操作:

  namespace hacker {
struct unique {}; //创建一个新的唯一类型以避免破坏ODR
template<>
std :: ostream&运算符<< < unique>(std :: ostream& amp; const Test< unique>&)
{
//如果Test< T>是一个外向,我可以访问和修改*任何*测试< T>!
// if Test< T>是一个内向,然后我只能搞砸与Test< unique>
//这不是很有趣...
}
}


I have read couple of the question regarding my problem on stackoverflow now, and none of it seems to solve my problem. Or I maybe have done it wrong... The overloaded << if I make it into an inline function. But how do I make it work in my case?

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;
}

解决方案

This is one of those frequently asked questions that have different approaches that are similar but not really the same. The three approaches differ in who you are declaring to be a friend of your function --and then on how you implement it.

The extrovert

Declare all instantiations of the template as friends. This is what you have accepted as answer, and also what most of the other answers propose. In this approach you are needlessly opening your particular instantiation D<T> by declaring friends all operator<< instantiations. That is, std::ostream& operator<<( std::ostream &, const D<int>& ) has access to all internals of 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
}

The introverts

Only declare a particular instantiation of the insertion operator as a friend. D<int> may like the insertion operator when applied to itself, but it does not want anything to do with std::ostream& operator<<( std::ostream&, const D<double>& ).

This can be done in two ways, the simple way being as @Emery Berger proposed, which is inlining the operator --which is also a good idea for other reasons:

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>
   }
};

In this first version, you are not creating a templated operator<<, but rather a non-templated function for each instantiation of the Test template. Again, the difference is subtle but this is basically equivalent to manually adding: std::ostream& operator<<( std::ostream&, const Test<int>& ) when you instantiate Test<int>, and another similar overload when you instantiate Test with double, or with any other type.

The third version is more cumbersome. Without inlining the code, and with the use of a template, you can declare a single instantiation of the template a friend of your class, without opening yourself to all other instantiations:

// 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> ...
}

Taking advantage of the extrovert

The subtle difference between this third option and the first is in how much you are opening to other classes. An example of abuse in the extrovert version would be someone that wants to get access into your internals and does this:

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...
   }
}

这篇关于重载朋友运算符&lt;为模板类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆