문제

다음과 같은 최소한의 예를 고려하십시오.

#include <iostream>

using namespace std;

class myostream : public ostream {
    public:
        myostream(ostream const &other) :
            ostream(other.rdbuf())
        { }
};

int main() {
    cout << "hello world" << endl;

    myostream s(cout);
    s << "hello world" << endl;

    myostream(cout) << "hello world" << endl;
}

G ++ 및 Visual C ++의 출력은 다음과 같습니다.

hello world
hello world
0x4012a4

임시 객체에 쓰는 버전, myostream(cout), 회원 연산자를 선호하는 것으로 보입니다 ostream::operator<<(void *), 무료 운영자 대신 operator<<(ostream &, char *). 객체의 이름이 있는지 여부는 차이를 만드는 것 같습니다.

왜 이런 일이 발생합니까? 그리고이 행동을 어떻게 방지합니까?

편집하다: 왜 그런 일이 발생 하는가가 이제 다양한 답변에서 분명합니다. 이를 방지하는 방법에 관해서는 다음이 매력적인 것 같습니다.

class myostream : public ostream {
    public:
        // ...
        myostream &operator<<(char const *str) {
            std::operator<<(*this, str);
            return *this;
        }
};

그러나 이것은 모든 종류의 모호성을 초래합니다.

도움이 되었습니까?

해결책

rvalues는 정점이 아닌 참조에 결합 할 수 없습니다. 따라서 당신의 예에서, Type Ostream의 임시는 자유 연산자의 첫 번째 인수가 될 수 없으며 (std :: ostream &, char const*), 사용되는 것은 멤버 연산자 << (void*)입니다.

필요한 경우 다음과 같은 통화를 추가 할 수 있습니다.

myostream(cout).flush() << "foo";

rvalue를 참조로 변환합니다.

C ++ 0X에서 RValue Reference의 도입은 연산자의 과부하를 제공 할 수 있습니다.

다른 팁

객체의 이름이없는 경우 (예 : 임시). 구체적으로, 그것은 첫 번째 매개 변수에 바인딩 될 수 없습니다.

operator<<(ostream &, char *)

나는 곧 깨달았다 부분 답의. 임시는 LValue가 아니므로 유형의 인수로 사용할 수 없습니다. ostream &.

"어떻게이 일을 할 수 있습니까?"라는 질문은 남아 있습니다 ...

지금까지의 대답은 깨끗한 솔루션을 제공하지 않는 것처럼 보이므로 더러운 해결책에 정착 할 것입니다.

myostream operator<<(myostream stream, char const *str) {
    std::operator<<(stream, str);
    return stream;
}

이것은 가능합니다 myostream 카피 생성자가 있습니다. (내부적으로, 그것은 Ref-counted에 의해 뒷받침됩니다 std::stringbuf.)

RValue 참조가 있기 때문에 C ++ 11 이이 문제를 해결하지만, 이것이 PRE-C ++ 11의 해결 방법 일 수 있다고 생각합니다.

솔루션은 멤버 기능 << 연산자가 기본 클래스에 대한 참조가 아닌 참조로 캐스팅 할 수있는 것입니다.

class myostream : public ostream {
    public:
        // ...
        template<typename T>
        ostream &operator<<(const T &t) {
            //now the first operand is no longer a temporary,
            //so the non-member operators will overload correctly
            return static_cast<ostream &>(*this) << t;
        }
};

글쎄, 나는 이것을 일으키는 C ++ 사양을 모르겠지만, 왜 그런 일이 발생하는지 쉽게 알 수 있습니다.

스택에 임시 생활을하고 일반적으로 다른 기능으로 전달되거나 단일 작업이 호출됩니다. 따라서 무료 연산자에게 전화하면 다음과 같습니다.

연산자 << (Myostream (cout))

이 작업의 끝에서 파괴되고 두 번째 "<<"연산자는 endl을 추가하여 유효하지 않은 객체를 참조 할 것입니다. 무료 "<<"연산자의 반환 값은 파괴 된 임시 대상에 대한 참조입니다. C ++ 사양은 아마도이 시나리오가 C ++ 프로그래머를 실망시키고 혼란스럽게하는 것을 방지하기 위해 무료 운영자에 대한 규칙을 정의 할 수 있습니다.

이제 임시의 "<< (void*)"멤버 연산자의 경우 리턴 값은 객체 자체이며, 여전히 스택에 있고 파괴되지 않으므로 컴파일러는 그것을 파괴하지 않고 통과하는 것을 알고 있습니다. 다음 멤버 연산자에게, Endl을 취하는 운영자에게. Temporaries의 연산자 체인은 간결한 C ++ 코드에 유용한 기능이므로 C ++ 사양 설계자가이를 고려하고 의도적으로 지원하기 위해 컴파일러를 구현했을 것입니다.

편집하다

어떤 사람들은 그것이 중요한 참조와 관련이 있다고 말했다. 이 코드는 다음과 같습니다.

#include <iostream>
using namespace std;
class myostream : public ostream { 
    public: 
        myostream(ostream const &other) : 
            ostream(other.rdbuf()) 
        { } 
            ~myostream() { cout << " destructing "; }
    }; 
int _tmain(int argc, _TCHAR* argv[])
{
    basic_ostream<char>& result = std::operator << (myostream(cout), "This works");
    std::operator << (result, "illegal");
         return 0;
}

그리고 그것은 돌아옵니다

  This works destructing illegal
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top