为什么我不能对带有模板参数的友元函数使用相同的模板参数?我的意思是下面的代码没问题!
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();
}
答案 0 :(得分:3)
您可以使用以下
template <class Vertex>
class Edge
{
friend ostream& operator<< <>(ostream& os, const Edge<Vertex>& e);
/// ...
};
使operator << <Vertex>
成为Edge
的朋友。
在你的第二种情况下 - 你做朋友非模板操作符,但是这个操作符的定义是模板,所以你有未定义的引用,但如果你希望你的operator <<
具体{{1},可以使用这种情况}(例如Edge
)。
答案 1 :(得分:2)
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)。
答案 2 :(得分:2)
问题在于:
friend ostream& operator<<(ostream& os, const Edge<Vertex>& e);
您正在声明一个非模板函数(将是
对于Edge
)的每个实例化而言,friend
不同,
而不是模板的实例化。
我见过的最常见的解决方案就是简单
在类模板中实现operator<<
内联
定义。或者,您可以提供公共会员
执行输出的函数,并从中调用它
operator<<
功能模板。或者你可以写:
friend ostream& operator<< <Vertex>(ostream&, Edge<Vertex> const& );
告诉编译器朋友的operator<<
是
模板的实例化。但是,IIUC只能起作用
如果有目标operator<<
功能的声明
此时模板可见,这意味着您需要
转发声明它(并为了转发声明它,到
forward声明类模板)。
我对此类问题的通常解决方案是提供
一个普通的成员函数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 )
{
// ...
}
};
我发现这通常会使代码更简单,更容易 最后关注。
答案 3 :(得分:1)
我认为最容易理解的是,如果我们消除了无关的噪音并考虑:
template <typename T>
struct X
{
friend void f(X<T>& x) { }
};
template <typename T>
void f(const X<T>& x) { }
f
内X
为:void f(X<T>& x)
f
以外X
为: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]
不是特别清楚,但是海湾合作委员会说的是后者的void f<double>(...)
。
就个人而言,我倾向于在类中定义函数...你根本不需要提到模板方面,只需:
friend ostream& operator<<(ostream& os, const Edge& e)
{
// use e.whatever...
}