2010-07-27 6 views
1

[EDIT - 오래 전 2,500 건의 "주목할만한 질문"이있을 때까지 여기를 잊어 버렸습니다. 사람들이보고 있기 때문에 허용 된 답변에서 과부하에 대한 유용한 정보가 있지만 구체적으로 std::endl을 확인하는 것은 당시에 깨달은 것보다 훨씬 나쁘고 분명히 잘못된 것입니다.오버로드 된 멤버 함수 문제의이 주소를 어떻게 해결할 수 있습니까?

기본적으로 std::endl의 효과는 \n을 스트림에 출력 한 다음 std::flush으로 플러시하는 것입니다. 그것은 플랫폼과 관계없이, 줄 끝이 실제로 "\ r \ n"인 Windows를 포함합니다. endl 매니퓰레이터는 플랫폼 차이점 WRT 라인이 끝나는 추상화를 수행하지 않으며, C++은 나중에 \n을 "\ r \ n"(바이너리가 아닌 텍스트 모드 용)으로 변환하여 C와 동일한 방식으로 처리합니다. 나는 C++이 뭔가 다른 것을하고 있다고 생각했다. 매우 강한 가정으로 20 년 동안 의문을 제기하지도 않았지만 틀렸다.

세부 정보는 기억하지 않지만 어쨌든 자신 만의 스트림을 정의하고 스트리밍되는 문자의 대체 출력 (및 변환)을 제공 할 수 있습니다. 모든 조작자가 앞에 사용자 스트림 코드 결과 출력 문자를 봅니다. 그래서 특별한 end-of-line 동작을 제공하려면 \n (텍스트 파일의 줄 끝 번역 이전에 있음)을 살펴보십시오. ]

hackish입니다.하지만 저는 최근에 표준 스트림처럼 작동 할 스트림 클래스를 구현해야했지만, std :: endl 매니퓰레이터와 특수한 경우를 감지 할 수 있습니다. 특정 메소드 구현에서 내 첫 번째 시도였다 ...이와

mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&)) 
{ 
    if (p == &std::endl) 
    { 
    // Handle special case 
    } 
    else 
    { 
    m_Underlying_Stream << p; 
    } 

    return *this; 
} 

말썽이 컴파일러는 내가 말하는 겁니다 std::endl의 어느 과부하 알고하지 않습니다. 다음과 같이 나는 ... 컴파일러 (그리고 또 다른 실험이 증명으로도 할당에 대한),하지만 operator==에 대한 초기화의 맥락에서 과부하를 해결할 수있다

mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&)) 
{ 
    typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&); 

    const ENDL_T l_ENDL (&std::endl); 

    if (p == l_ENDL) 
    { 
    // Handle special case 
    } 
    else 
    { 
    m_Underlying_Stream << p; 
    } 

    return *this; 
} 

그것을 해결.

문제의 컴파일러는 MinGW GCC 4.4.0이지만 컴파일러 문제 일 가능성은 낮습니다.

나는 누락 된 const를 갈 필요가있는

How to get the address of an overloaded member function?

내 코드가 CONST 문제가있는 경우

은 몰라요 ... 주변의 모습을했고이 질문을 발견했다. 다른 명백한 유형 문제는 볼 수 없습니다.

나는 WRT 오버로드 또는 암시 적 캐스팅과 관련하여 모호한 아이디어를 가지고 있지만 구체적인 내용은 없습니다. 그래서 - 첫 번째 예제에서 무엇이 잘못 되었는가, 두 번째 버전에서 수정 된 이유, 함수의 주소를 사용할 때 어떤 과부하가 나는지를 안전하게 설명 할 수있는 사람은 누구든지 명확하게 설명 할 수 있습니까?

BTW - 나는 사람들이 나를 std::endl의 주소로 직접 테스트하는 것을 좋아하지 않을 것이라고 추측 할 수 있으며, 이것이 깨지기 쉽다는 것을 알 수 있습니다. 누군가 내가 직접 찾아 볼 수없는 std::endl을 호출하는 자신 만의 조작기를 가질 수 있습니다. 일반적으로 이것은 사실이지만,이 특별한 경우에는 해킹으로 많은 시간을 절약 할 수 있으며 불결함은 중요하지 않습니다.

+0

작품을 나를 위해. _ – kennytm

답변

2

의 "주소와 같은 인수 (없이 오버로드 된 함수 이름 (또는 오버로드 된 함수의 집합처럼 동작하는 함수 템플릿의 이름)의 사용 "표현식)은 컨텍스트가 필요한 특정 오버로드를 고유하게 결정하는 데 사용할 수있는 제한된 컨텍스트 집합에서만 허용됩니다.

표준 (ISO/IEC 14882 : 2003) [over.over]의 13.4에 지정되어 있습니다. 객체 또는 참조 또는 명시 적 변환의 초기화자가 포함됩니다. 이렇게하면 여러 가지 옵션이 제공됩니다.

예. 명시 적 변환 :

typedef std::ostream& (*ManipPtr)(std::ostream&); 

mystream& mystream::operator<<(ManipPtr p) 
{ 
    if (p == static_cast<ManipPtr>(&std::endl)) 
    { 
     // ... 

는 직접 포인터를 초기화 :

typedef std::ostream& (*ManipPtr)(std::ostream&); 

mystream& mystream::operator<<(ManipPtr p) 
{ 
    const ManipPtr pEndl = &std::endl; 

    if (p == pEndl) 
    { 
     // ... 
+0

감사합니다 - 완벽한 답변처럼 보입니다. – Steve314

+0

사실, 두 번째 생각에, 나는 여전히'operator <<'가 적절한 문맥을 제공 할 수 있지만'operator =='이 왜 그렇게 할 수 없는지에 대해서는 분명하지 않다. 예를 들어'operator =='의 과부하가 모호한가? – Steve314

+0

스트림상의'operator <<'가 멤버 함수이지만 함수 포인터의'operator =='가 표준 비 멤버 함수이기 때문에이 차이가있을 수 있습니까? – Steve314

0

오버로드를 구분할 수없는 이유는 함수의 주소를 확인하고 호출하지 않기 때문입니다. 스트림에 삽입하면 컴파일러에서 endl(ostream&) 오버로드를 호출하는 것을 알고 있습니다. 그것 이외에, 너 혼자 야.

왜 '\ n'을 테스트하지 않는 것이 좋을까요?

+2

그것은 의도 한 행동과 다를 것입니다. 'std :: endl'은 **이 아니라 '\ n'과 같은 것입니다. – acanaday

+0

왜 함수가 오버로드 되었기 때문에 함수 주소를 볼 수 없어야합니까? 그리고주의하십시오 - 저는 중간 변수를 사용할 때 성공적으로 그 일을합니다. – Steve314

+0

@acanaday - 절대적으로 정확합니다. – Steve314

1

다음 작품 :

#include <iostream> 

struct mystream { 
    typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&); 
    mystream& operator<< (ENDL_T p) 
    { 
     if (p == (ENDL_T)std::endl) 
     { 
      std::cout << "special case\n"; 
     } 
     else 
     { 
      std::cout << "usual case\n"; 
     } 
     return *this; 
    } 
}; 

int main() 
{ 
    mystream ms; 
    ms << std::endl; // prints "special case" 
    ms << std::flush; // prints "usual case" 
} 
+1

... 또는 @Charles Bailey의 static_cast. 그건 그렇고, 이런 종류의 오버로드 해상도는'transform (s.begin(), s.end(), s.begin(), (int (*) (int)) toupper를 구현할 때 모든 텍스트 북에서 실행되는 것이다. 문자열의 경우. – Cubbi

+0

'transform'에 대한 흥미로운 점. – Steve314

관련 문제