2014-01-14 44 views
5

处理项目我没有启动,我想将<<运算符添加到类中。问题:班级是其他班级的私人内部班级,后者在namespaceC++定义内部类的<<运算符

而且我做不到。

问题可以简化这种方式:

#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(不幸)。

+0

您的代码与Visual C++编译器版本15.0(即VS2008,pre C++ 11)一起使用。你正在使用哪种编译器?在ideone.com上不起作用.... –

+0

我没有在那里看到内部类。只是名称空间中的常规类。 – RedX

+0

@TonyD:好问题,我相应地更新了文字。我用普通的g ++:gcc版本4.8.1(Ubuntu/Linaro 4.8.1-10ubuntu9)。 – unamourdeswann

回答

8

由于friend运算符是在类中首次声明的,它只能通过依赖于参数的查找来使用。但是,它们的参数类型都不在namespace A中,因此不会被找到。 Cstd::map的别名,因此在ADL中被认为是namespace std

有多种方法,你可以解决它,没有一个是完美的:

  • 声明功能namespace A类定义之前;然后通过正常查找变得可用,而不仅仅是ADL。但是,这会在某种程度上破坏封装,并且如果有其他任何尝试将过载为std::map,可能会导致问题。
  • 用命名静态(非朋友)函数替换运算符重载,并按名称调用它。
  • 声明C作为内部类,而不是std::map的别名。这可以在不破坏封装的情况下实现ADL,但如果您希望它的行为如同std::map那样有点尴尬。
+0

+1这是迄今唯一正确的答案。 – ereOn

+0

看起来不错!但是我用'A :: operator <<(std :: cout,a);'替换了'std :: cout << a << std :: endl;',并且我得到了'error:'operator <<'不是'A''的成员。我做错了吗? – unamourdeswann

+0

@ user980053:对不起,现在我想起来也不行,操作员只能*通过ADL找到。就个人而言,我可能会放弃重载'<<'的想法并编写一个像'static void B :: print(std :: ostream&os,const C&c)'这样的命名函数。 –

1

根据Mike Seymour的回答,下面是第一个解决方案的示例。 注意运算符< <()应该在类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; 
    } 
} 
+0

酷!唯一的缺点是我现在为'namespace A'的每个'map '定义'operator <<'。我希望我可以将定义限制为'C' ... – unamourdeswann