2014-01-14 22 views
5

プロジェクトに取り組みませんでした。<<演算子をクラスに追加したいと思います。問題:クラスは他のクラスのプライベート内部クラスであり、後者はnamespaceにあります。C++内部クラスの<<演算子を定義する

私はそれを作ることができません。

問題は、この方法を簡素化することができます。

#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

フレンドオペレータは、クラス内で最初に宣言されるため、引数依存ルックアップによってのみ使用できます。しかし、どちらのパラメータタイプもnamespace Aにはないので、それは見つからないでしょう。 Cstd::mapの別名であるため、ADLの目的ではnamespace stdとみなされます。

あなたが完璧であるのどれも、それを修正することができ、様々な方法があります。

  • は、クラス定義の前namespace Aで関数を宣言していないが、 ADLだけでなく、通常のルックアップによって利用可能になります。しかし、これによりカプセル化がやや破綻し、他のものがstd::mapのためにoperator<<をオーバーロードしようとすると問題が発生する可能性があります。
  • オペレータのオーバーロードを名前付きスタティック(フレンドでない)関数に置き換え、名前でコールします。
  • std::mapのエイリアスではなく、内部クラスとしてCを宣言します。これにより、カプセル化を破ることなくADLが可能になりますが、std::mapのように動作させたい場合は少し面倒です。
+0

+1これまでの唯一の正解です。 – ereOn

+0

いいね!しかし、 'std :: cout << a << std :: endl;を' :: operator <<(std :: cout、a); 'で置き換えました。' error: 'operator <<'は'A'のメンバーではありません。私はそれを間違っていたのですか? – unamourdeswann

+0

@ user980053:申し訳ありませんが、今私はそれについてもうまくいかないと思います。オペレータはADLによって*のみ*を見つけることができます。個人的には、私はおそらく '<<'をオーバーロードし、 '' static void B :: print(std :: ostream&os、const C&c) 'のような名前付き関数を書く考えをあきらめています。 –

1

マイクシーモアの答えに基づいて、ここに最初の解決策の例があります。 オペレータ< <()はクラス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

関連する問題