C ++에서 암시 적 변환을 통해 운영자를 찾을 수 없습니다.
-
05-09-2019 - |
문제
힙으로 배치 된 물체 주위에 래퍼 역할을하기 위해 클래스를 작성할 때, 나는이 간단한 예로 줄일 수있는 암시 적 유형 변환에 문제가 발생했습니다.
아래 코드 아래에서 래퍼 클래스는 힙으로 배치 된 객체를 관리하고 암시 적으로 해당 객체에 대한 참조로 변환합니다. 이것은 암시 적 변환이 발생하기 때문에 함수 쓰기 (...)에 대한 인수로서 래퍼 객체를 전달할 수있게한다.
그러나 명시 적 캐스트가 이루어지지 않는 한 (MSVC8.0, Intel 9.1 및 GCC 4.2.1 컴파일러로 확인).
(1)이 경우 암시 적 변환이 실패하는 이유는 무엇입니까? (2) 인수 의존적 조회와 관련이있을 수 있습니까? 그리고 (3) 명백한 캐스트 없이이 일을하기 위해 할 수있는 일이 있습니까?
#include <fstream>
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
void write(std::ostream& os)
{
os << "(1) Hello, world!\n";
}
int main()
{
wrapper<std::ostream> file(new std::ofstream("test.txt"));
write(file);
static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
// file << "(3) This line doesn't compile!\n";
}
해결책
당신이 당신의 운영자를 해결하려고 노력하기 때문에 실패합니다. wrapper<T>
존재하지 않는 클래스. 캐스트없이 작동하기를 원한다면 다음과 같은 것을 모을 수 있습니다.
template<typename X> wrapper<T> &operator <<(X ¶m) const {
return t << param;
}
불행히도 컴파일 시간에 리턴 유형을 해결하는 방법을 모릅니다. 다행히도 대부분의 경우이 경우를 포함하여 객체와 동일한 유형입니다. ostream
.
편집하다: 대시-톰-뱅의 제안에 의해 수정 된 코드. 반환 유형이 변경되었습니다 wrapper<T> &
.
다른 팁
컴파일러는이를 결정하기에 충분한 컨텍스트가 없습니다 operator&
유효한 변환을 할 것입니다. 그렇습니다. 이것은 인수 의존적 조회와 관련이 있다고 생각합니다. 컴파일러는 operator<<
비를 받아 들일 수 있습니다const
wrapper<std::ostream>
첫 번째 매개 변수로.
문제는 컴파일 타임 제약 조건을 유지하는 것과 관련이 있다고 생각합니다. 예에서는 컴파일러가 먼저 찾아야합니다. 모두 가능한 연산자 <<. 그런 다음 각각의 경우 객체를 각 연산자 <<이 허용 할 수있는 유형으로 자동으로 (직접 또는 간접적으로) 자동으로 변환 할 수 있는지 시도해야합니다.
이 테스트는 정말 복잡 할 수 있으며, 이것이 합리적인 컴파일 시간을 제공하는 것으로 제한된다고 생각합니다.
일부 테스트 후에는 더 단순한 예제가 문제의 원인을 식별합니다. 컴파일러는 템플릿 인수를 추론 할 수 없습니다 T
안에 f2(const bar<T>&)
아래의 암시 적 변환에서 wrapper<bar<int> >
에게 bar<int>&
.
template <typename T>
class wrapper
{
T* t;
public:
explicit wrapper(T * const p) : t(p) { }
~wrapper() { delete t; }
operator T & () const { return *t; }
};
class foo { };
template <typename T> class bar { };
void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }
int main()
{
wrapper<foo> s1(new foo());
f1(s1);
wrapper<bar<int> > s2(new bar<int>());
//f2(s2); // FAILS
f2<int>(s2); // OK
f3(s2);
}
원래 예에서 std::ostream
실제로 a typedef
템플릿 클래스의 경우 std::basic_ostream<..>
, 템플릿 함수를 호출 할 때 동일한 상황이 적용됩니다. operator<<
.
삽입 연산자의 서명을 확인하십시오.
확인 C ++ 03 표준을 사용하여 Char* 출력 연산자의 서명은 다음과 같습니다.
template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
실제로는 중요한 참조를 취합니다. 따라서 변환 연산자가 일치하지 않습니다.
의견에 언급 된 바와 같이 : 이것은 관련이 없습니다.
적용된 전환에 대한 표준에는 다양한 제한이 있습니다 ... 아마도 최대 하나를 적용해야 할 때는 암시 적 변환 (연산자 및 기본 유형으로 캐스트)이 필요할 수 있습니다.