임시와 관련된 운영자 과부하 해상도의 순서
-
20-09-2019 - |
문제
다음과 같은 최소한의 예를 고려하십시오.
#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