繁体   English   中英

operator <<(ostream&os,...)用于模板类

[英]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 EdgeEdge<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM