![](/img/trans.png)
[英]operator<<(ostream&, X) for class X nested in a class template
[英]operator<<(ostream& os, …) for template class
为什么我不能对带有模板参数的友元函数使用相同的模板参数? 我的意思是下面的代码没问题!
template <class Vertex>
class Edge
{
template <class T>
friend ostream& operator<<(ostream& os, const Edge<T>& e);
/// ...
};
template <class T>
ostream& operator<<(ostream& os, const Edge<T>& e)
{
return os << e.getVertex1() << " -> " << e.getVertex2();
}
但是这个不行。 为什么? 问题是什么? (我得到链接器错误。)
template <class Vertex>
class Edge
{
friend ostream& operator<<(ostream& os, const Edge<Vertex>& e);
/// ...
};
template <class T>
ostream& operator<<(ostream& os, const Edge<T>& e)
{
return os << e.getVertex1() << " -> " << e.getVertex2();
}
你可以使用以下
template <class Vertex>
class Edge
{
friend ostream& operator<< <>(ostream& os, const Edge<Vertex>& e);
/// ...
};
这使operator << <Vertex>
朋友变为Edge
。
在你的第二种情况下 - 你做朋友非模板操作符,但是这个操作符的定义是模板,所以你有未定义的引用,但是如果你想要你的operator <<
for concrete Edge
( Edge<int>
,可以使用这种情况)。
template <class T>
friend ostream& operator<<(ostream& os, const Edge<T>& e);
说,有模板化的 operator <<
外面,与它成为朋友,一切都好。
friend ostream& operator<<(ostream& os, const Edge<Vertex>& e);
说,有一个operator <<
外面,成为它的朋友......而且编译器找不到这样的东西。
为了告诉编译器操作符是模板化的,请按照ForEveR提到的<>
帮助他(他快速击败我:-D)。
问题在于:
friend ostream& operator<<(ostream& os, const Edge<Vertex>& e);
您声明非模板函数(对于Edge
每个实例化将是不同的)是friend
,而不是模板的实例化。
我在这里看到的最常见的解决方案是在类模板定义中简单地实现operator<<
inline。 或者,您可以提供执行输出的公共成员函数,并从operator<<
function template中调用它。 或者你可以写:
friend ostream& operator<< <Vertex>(ostream&, Edge<Vertex> const& );
告诉编译器operator<<
哪个是朋友是模板的实例化。 但是,只有当目标operator<<
功能模板在此处可见时,这意味着您需要转发声明它(并且为了转发声明它,转发声明类模板),这只适用于IIUC。 。
我对此类问题的通常解决方案是提供普通的成员函数print
,然后派生自:
template <typename DerivedType>
class IOStreamOperators
{
public:
friend std::ostream&operator<<(
std::ostream& dest,
DerivedType const& source )
{
source.print( dest ) ;
return dest ;
}
friend std::istream&operator>>(
std::istream& source,
DerivedType& dest )
{
dest.scan( source ) ;
return source ;
}
protected:
~IOStreamOperators() {}
};
,例如:
template <class Vertex>
class Edge : public IOStreamOperators<Edge<Vertex> >
{
// ...
void print( std::ostream& dest )
{
// ...
}
};
我发现这通常会使代码更简单,更容易理解。
我认为最容易理解的是,如果我们消除了外来噪音并考虑:
template <typename T>
struct X
{
friend void f(X<T>& x) { }
};
template <typename T>
void f(const X<T>& x) { }
X
里面的f
是: void f(X<T>& x)
X
外的f
是: void f<T>(X<T>& x)
您可以通过编译和查看生成的符号来获得一些提示:
00410aa8 t .text$_Z1fR1XIdE
00410ad4 t .text$_Z1fIdEvRK1XIT_E
从每个产品中调用GCC的__PRETTY_FUNCTION__ :
void f(X<double>&)
void f(const X<T>&) [with T = double]
不是特别清楚,但GCC的方式是说后者的void f<double>(...)
。
就个人而言,对于模板,我倾向于在类中定义函数...您根本不需要提及模板方面,只需:
friend ostream& operator<<(ostream& os, const Edge& e)
{
// use e.whatever...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.