2016-08-06 15 views
3

ユーザー定義のネームスペースのクラスに< <演算子をオーバーロードしようとしています。興味深いのは、すべての名前空間のものを削除すると、プログラムは問題なくコンパイルされて実行されますが、クラスが名前空間に存在するという事実によって、ファイルA.cppのコンパイルプロセスが失敗し、 mクラスのプライベートデータにアクセスしようとしています(demo.cppはうまくコンパイルされます)。フレンド関数とネームスペース

demo.cpp:

#include <iostream> 
#include "A.h" 


int main() { 
    usr::A a(4); 
    std::cout << a << std::endl; 


    return 0; 
} 

ああ:

#ifndef A_H_ 
#define A_H_ 

#include <iostream> 


namespace usr { 
    class A { 
     private: 
      int m_x; 
     public: 
      A(int x); 
      friend std::ostream& operator<<(std::ostream& os, const usr::A& a); 
    }; 
} 

#endif // A_H_ 

A.cpp:

私の3ファイルのプログラムと私が手コンパイルエラーを見て、ください。
#include "A.h" 


usr::A::A(int x) : m_x(x) {} 

std::ostream& operator<<(std::ostream& os, const usr::A& a) { 
    os << a.m_x; 
    return os; 
} 

エラー:

$ g++ -c A.cpp 
In file included from A.cpp:1:0: 
A.h: In function ‘std::ostream& operator<<(std::ostream&, const usr::A&)’: 
A.h:10:17: error: ‘int usr::A::m_x’ is private 
      int m_x; 
       ^
A.cpp:7:13: error: within this context 
    os << a.m_x; 
      ^
+0

関連する質問:http://stackoverflow.com/questions/30418270/clang-bug-namespaced-template-class-friend –

答えて

7

非公開の友人宣言は、常に、最も小さい囲み名前空間のメンバーを参照します。クラスがネームスペースusrで宣言されている場合、そのクラス内の非修飾フレンド宣言は、usrのメンバーを参照します。私。あなたの友人宣言はusr::operator <<を友人として宣言しました。

グローバル::operator <<は、この場合は友人ではないため、usr::Aのプライベートメンバーにアクセスしようとすると、エラーが発生するのは、::operator <<です。

あなたはこれが仕事をしたい場合は、あなたがあなたのoperator <<usrのメンバー、または

  • はfriend宣言が明示的に修飾を使用して、グローバルoperator <<を指していることを確認してくださいいずれかのために

    1. 持っています::operator <<(これには、の修飾名で参照しようとする前に、::operator <<を導入する必要があります)。

    私は最初のアプローチを提案します。クラスAがネームスペースusrのメンバーである場合は、を処理するすべての関数をメンバーとしてusrとして宣言することをお勧めします。これは、引数依存ルックアップ(ADL)に関する多くの問題を回避するのに役立ちます。


    しかし、あなたはあなたのoperator <<がグローバル名前空間のメンバーを維持する必要があるいくつかの理由のために、そして、ここでフープをしている場合は、(単一の翻訳単位にまとめ)

    それをコンパイルするために介してジャンプする必要があると思います

    // Pre-declare `usr::A` to enable pre-declaration of our `::operator <<` 
    namespace usr { 
        class A; 
    } 
    
    // Pre-declare our `::operator <<` 
    std::ostream& operator<<(std::ostream& os, const usr::A& a); 
    
    namespace usr { 
        class A { 
         private: 
          int m_x; 
         public: 
          A(int x); 
          friend std::ostream& ::operator<<(std::ostream& os, const usr::A& a); 
          // Friend declaration uses qualified name - it explicitly 
          // refers to `::operator <<` declared above 
        }; 
    } 
    
    usr::A::A(int x) : m_x(x) {} 
    
    std::ostream& operator<<(std::ostream& os, const usr::A& a) { 
        os << a.m_x; 
        return os; 
    } 
    
    int main() { 
        usr::A a(4); 
        std::cout << a << std::endl; 
    } 
    
  • 関連する問題