C++ 为模板类重载友元运算符<<
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4660123/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
overloading friend operator<< for template class
提问by starcorn
I have read couple of the questions regarding my problem on StackOverflow.com now, and none of it seems to solve my problem. Or I maybe have done it wrong...
The overloaded <<
works if I make it into an inline function. But how do I make it work in my case?
我现在已经在 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
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
The code:
编码:
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;
}
回答by David Rodríguez - dribeas
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>
.
将模板的所有实例声明为朋友。这是您已接受的答案,也是大多数其他答案的建议。在这种方法中,您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
}
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>& )
.
仅将插入运算符的特定实例声明为友元。D<int>
在应用于自身时可能喜欢插入运算符,但它不想与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:
这可以通过两种方式完成,一种简单的方式是@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>
}
};
In this first version, you are notcreating 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.
在第一个版本中,您不是在为模板operator<<
的每个实例化创建一个模板化的函数,而是创建一个非模板化的函数Test
。同样,差异是微妙的,但这基本上等同于手动添加:std::ostream& operator<<( std::ostream&, const Test<int>& )
当您实例化时Test<int>
,以及当您Test
使用double
或任何其他类型实例化时另一个类似的重载。
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 allother 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 extrovertversion 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...
}
}
回答by Nim
You can't declare a friend like that, you need to specify a different template type for it.
你不能像那样声明一个朋友,你需要为它指定一个不同的模板类型。
template <typename SclassT>
friend ostream& operator<< (ostream & os, const D<SclassT>& rhs);
note SclassT
so that it doesn't shadow classT
. When defining
请注意SclassT
它不会产生阴影classT
。定义时
template <typename SclassT>
ostream& operator<< (ostream & os, const D<SclassT>& rhs)
{
// body..
}
回答by EmeryBerger
This worked for me without any compiler warnings.
这对我有用,没有任何编译器警告。
#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;
}
回答by Alessandro Teruzzi
I think you shouldn't make friend in the first place.
我认为你首先不应该交朋友。
You can create a public method call print, something like this (for a non template class):
您可以创建一个公共方法调用打印,如下所示(对于非模板类):
std::ostream& MyClass::print(std::ostream& os) const
{
os << "Private One" << privateOne_ << endl;
os << "Private Two" << privateTwo_ << endl;
os.flush();
return os;
}
and then, outside the class (but in the same namespace)
然后,在类之外(但在同一个命名空间中)
std::ostream& operator<<(std::ostream& os, const MyClass& myClass)
{
return myClass.print(os);
}
I think it should work also for template class, but I haven't tested yet.
我认为它也适用于模板类,但我还没有测试过。
回答by John Dibling
Here you go:
干得好:
#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;
}