2016-08-06 3 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 :

#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 <<::operator <<에서 usr::A의 private 멤버에 액세스하려고 할 때 오류가 왜이 경우에 비 친구 남아있다. 이 작업 할 경우

, 당신은

  1. 는 친구의 선언은 명시 적으로 자격을 사용하여 글로벌 operator <<를 참조하십시오 당신의 operator <<usr의 구성원 또는

  2. 을 확인하는 중 하나가 이름 ::operator << (해당 이름을 사용하여을 참조하기 전에 ::operator <<을 입력해야합니다.)

나는 첫 번째 접근법을 제안 할 것이다. 클래스 A이 네임 스페이스 usr의 멤버 인 경우 A을 처리하는 모든 함수를 usr의 멤버로 선언하는 것이 좋습니다. 이렇게하면 ADL (argument-dependent lookup)과 관련된 많은 문제를 피할 수 있습니다.


그러나 당신이 당신의 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; 
}