C ++定义<<内部阶级的操作者

时间:2014-01-14 08:46:46

标签: c++ operator-overloading header-files

处理我没有启动的项目,我想在类中添加<<运算符。问题:该类是另一个类的私有内部类,后者位于namespace

我做不到。

可以通过这种方式简化问题:

#include <iostream>
#include <map>
namespace A {
    class B {
        private:
            typedef std::map<int, int> C;
            C a;
            friend std::ostream& operator<<(std::ostream& os, const C &c) {
                for (C::const_iterator p = c.begin(); p != c.end(); ++p)
                    os << (p->first) << "->" << (p->second) << " ";
                return os;
            }
        public:
            B() {
                a[13] = 10;
                std::cout << a << std::endl;
            }
        };
}
int main() {
    A::B c;
}

我尝试使用g++ test.cpp编译它:error: no match for ‘operator<<’。编译器找不到我的重载函数。我认为在标题中定义它会更简单,没有运气。如果您认为它更合适,我也可以在CPP文件中定义该类,但我不知道该怎么做。

最后一项要求,我不能使用C ++ 11(不幸的是)。

2 个答案:

答案 0 :(得分:8)

由于友元运算符首先在类中声明,因此它只能通过依赖于参数的查找来实现。但是,它的参数类型都不在namespace A中,因此无法找到。 Cstd::map的别名,因此出于ADL的目的被视为namespace std

有多种方法可以修复它,但没有一种方法是完美的:

  • 在类定义之前声明namespace A中的函数;然后它通过正常查找变得可用,而不仅仅是ADL。但是,这会在一定程度上打破封装,如果其他任何事情试图为operator<<重载std::map,可能会导致问题。
  • 使用命名的静态(非朋友)函数替换运算符重载,并按名称调用它。
  • C声明为内部类,而不是std::map的别名。这样可以在不破坏封装的情况下启用ADL,但如果您希望它的行为与std::map类似,则会有点尴尬。

答案 1 :(得分:1)

根据Mike Seymour的回答,这是第一个解决方案的示例。 注意运算符&lt;&lt;()应该在B类之外定义,并且暴露B :: C的实数类型。它不完美但可读......

namespace A {

  // It has to expose the B::C's type
  std::ostream& operator<<(std::ostream& os, const std::map<int, int> &c);

  class B {
  private:
    typedef std::map<int, int> C;
    C a;
    friend std::ostream& operator<<(std::ostream& os, const B::C &c);
  public:
      B() {
        a[13] = 10;
        std::cout << a << std::endl;
      }
    };

  std::ostream& operator<<(std::ostream& os, const B::C &c) {
    for (B::C::const_iterator p = c.begin(); p != c.end(); ++p) {
      os << (p->first) << "->" << (p->second) << " ";
    }
    return os;
  }
}