【问题标题】:How to declare operator<< for internal class如何为内部类声明 operator<<
【发布时间】:2011-06-29 12:26:42
【问题描述】:
//cannot declare operator<<(...) here:
//forward declarations:
class External;

template<class T, class Y>
class External::Internal;

template<class T, class Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T,Y>&);

class External
{
    template<class T, class Y>
    class Internal
    {};

    Internal data_;

    void print() {
        /*out is a std::ostream*/
        out << data_;
    }
};

template<class T, class Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T,Y>&)
{ }

我确实想为Internal 实现operator&lt;&lt;,但是当我尝试使用来自External 的此运算符调用时出现问题:在此运算符的定义下声明此运算符时,它看不到此运算符类,并且似乎无法在此类定义之上声明此运算符。

【问题讨论】:

  • 为什么Internal 没有正确限定?

标签: c++ templates operator-overloading forward-declaration nested-class


【解决方案1】:

如果您要问如何将Internal&lt;&gt;::operator&lt;&lt; 定义为朋友,那么:

class External
{
  template<class T, class Y>
  class Internal
  {
    friend std::ostream& operator <<(std::ostream& out, const Internal&)
    {
      // impl
      return out;
    }
  };

  Internal<Foo, Bar> data_;

public:
  void print() const
  {
    /*out is a std::ostream*/
    out << data_;
  }
};

【讨论】:

  • @ildjarn 感谢它现在有效。但是为了编译你应该从操作符中删除模板
  • @smallB : "但是为了编译你应该从操作符中删除模板" 嗯?运算符是一个模板,所以显然它必须被定义为一个模板。这按原样编译。
  • @ildjarn 不想在 VS2010 sp1 中编译。
  • @ildjarn 那么你为什么在之前的评论中说它可以编译?
  • @smallB :因为它是在我测试的编译器上完成的,它不是 VC++。
【解决方案2】:

Armen 的答案适用于 &lt;&lt; 运算符本身。

但是,您的成员声明

Internal data_;

也是不正确的,以同样的方式。即,缺少Internal 的模板参数。因此,除了修复您的运营商实现之外,还要修复您的成员声明。

最后,请记住,在 C++ 中,除非已经声明,否则您不能使用某些东西。您在 print 的内联实现中使用 &lt;&lt; 违反了这一点。所以你最好重新安排一些东西(或者只是声明它们),这样任何使用的东西都已经被声明了。

干杯,

【讨论】:

  • +1,当我下棋时,这一直是我的问题——我专注于棋盘的一部分,而不是整个棋盘:)
  • no Armen 的回答是行不通的。 operator
  • @smallB:您可能在某些旧版本的 MSVC 中遇到编译器错误(或者就此而言,最新版本尚未检查)?似乎在这里至少有两个答案给出了合适的前向声明。
【解决方案3】:

关键在于使用前向声明:

// you promise there will be implementation of this stuff later on:
template<typename T, typename Y>
class External::Internal<T, Y>;

template<typename T, typename Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T, Y>&);

// now declare your class and operator<< function as normal
class External
{
    template<class T, class Y>
    class Internal
    {
    };

    Internal<Foo, Bar> data_;

    void print()
    {
        // here you can use operator<< with Internal
        out << data_;
    }
};

template<class T, class Y>
std::ostream& operator<<(std::ostream& out,const External::Internal<T, Y>&)
{
}

【讨论】:

  • 你尝试编译它吗?试试看。
  • 对。 Internal 是私人的,我没有意识到这一点。在这种情况下,正如其他人所建议的那样,声明 friend 函数可能是可行的方法。
【解决方案4】:
template<class T, class Y>
std::ostream& operator<<(std::ostream& out,const External::Internal<T, Y>&)
                                                 ^^^^^^^^^^        ^^^^^^
{

}

并确保将此函数声明为friend,因为InternalExternal 中是私有的

更新: 这是您如何声明朋友的方法。在你的类定义中写:

template<class T, class Y>
friend  std::ostream& operator <<(std::ostream& out, const External::Internal<T,Y>&)

由于friend-declaration是一个声明,这将解决您的前向声明问题。

更新:解决循环依赖:

首先向前声明internal

template<class T, class Y>
class Internal;

然后声明朋友。

那么你的其他班级应该可以工作了。

【讨论】:

  • @Armen 我确实按照您的建议拥有它,但问题在于该运算符的前向声明。
  • @small B:什么意思?如何声明为好友?
  • @smallB :什么前向声明?您的代码没有显示。
  • @ildjarn 所以尝试制作我提供的代码存根并尝试编译它,然后你会看到真正的问题在哪里。
  • @smallB :描述你的问题是你的工作;独立解决不是我的。
【解决方案5】:
template<class T, class Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T, Y>&)
{
}

External:: 表现为命名空间,并且是必需的,因为 operator&lt;&lt; 定义在 External 类之外。

【讨论】:

    【解决方案6】:

    当我尝试从外部使用此操作员调用时出现问题

    不要在类定义中编写过程代码。只有声明。

    按顺序写:

    • 类定义[在标题中]
    • operator&lt;&lt; [在标题中]
    • 使用这些东西的代码 [在源文件中]

    【讨论】:

      猜你喜欢
      • 2019-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多