[英]overloading friend operator<< for template class
我现在已经在 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;
}
这是常见问题之一,这些问题的方法相似但并不完全相同。 这三种方法的不同在于你声明谁是你的函数的朋友——然后是你如何实现它。
外向的
将模板的所有实例声明为朋友。 这是您已接受的答案,也是大多数其他答案的建议。 在这种方法中,您通过将所有operator<<
实例化的朋友声明为不必要地打开了您的特定实例化D<T>
。 也就是说, 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
}
内向者
仅将插入运算符的特定实例声明为友元。 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>
}
};
在第一个版本中,您不是在为Test
模板的每个实例创建一个模板化的operator<<
,而是一个非模板化的函数。 同样,差异是微妙的,但这基本上等同于手动添加: 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> ...
}
利用外向的人
第三个选项和第一个选项之间的细微差别在于您对其他课程开放的程度。 外向版本中滥用的一个例子是有人想要进入你的内部并这样做:
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...
}
}
你不能像那样声明一个朋友,你需要为它指定一个不同的模板类型。
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;
}
我认为你首先不应该交朋友。
您可以创建一个公共方法调用打印,如下所示(对于非模板类):
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);
}
我认为它也适用于模板类,但我还没有测试过。
干得好:
#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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.