2009-08-07 8 views
2

Windows 코드를 Linux로 이식하는 동안 GCC 4.2.3에서 다음 오류 메시지가 나타납니다. (예, 나는 약간의 이전 버전 있다고 알고 있어요,하지만 난 쉽게 업그레이드 할 수 없습니다.) 나는이 오류를 생성하려면 다음 코드를 사용하고C++ 연산자 오버로드 - 클래스에서 캐스팅

main.cpp:16: error: call of overloaded ‘list(MyClass&)’ is ambiguous 
/usr/include/c++/4.2/bits/stl_list.h:495: note: candidates are: std::list<_Tp, _Alloc>::list(const std::list<_Tp, _Alloc>&) [with _Tp = unsigned char, _Alloc = std::allocator<unsigned char>] 
/usr/include/c++/4.2/bits/stl_list.h:484: note:     std::list<_Tp, _Alloc>::list(size_t, const _Tp&, const _Alloc&) [with _Tp = unsigned char, _Alloc = std::allocator<unsigned char>] 

.

#include <list> 
class MyClass 
    { 
    public: 
     MyClass(){} 

     operator std::list<unsigned char>() const { std::list<unsigned char> a; return a; } 
     operator unsigned char() const { unsigned char a; return a; } 

    }; 

    int main() 
    { 
     MyClass a; 
     std::list<unsigned char> b = (std::list<unsigned char>)a; 

     return 0; 
    } 

이 오류가 발생 했습니까? 더 중요하게, 그것의 주위에 얻는 방법? (그것은 완전히 GetList() 등 기능과 같은 GetChar()를 사용하여, 확인, 과부하를 피하기 위해 가능하지만, 나는 그것을 방지하고 싶습니다.)

(그런데, "operator unsigned char()는"오류를 제거하는 제거.)

답변

1

캐스트를 제거하면 올바르게 컴파일되고 연산자 std :: list가 실행되고 있는지 확인했습니다.

int main() 
{ 
    MyClass a; 
    std::list<unsigned char> b = a; 

    return 0; 
} 

또는 const 참조로 캐스팅 한 경우.

int main() 
    { 
     MyClass a; 
     std::list<unsigned char> b = (const std::list<unsigned char>&)a; 

     return 0; 
    } 
+0

왜 그렇습니까? 당신이 암시 적으로 오버로드 된 캐스팅을 호출 할 수 있다는 사실을 알고 있습니다. –

+0

죄송합니다. 명시 적으로 전화하십시오. –

+0

확실히 모르겠다. 명시 적으로 operator를 (캐스팅하여) 사용하고 싶다고 가정하지 않는다면, 먼저 표준 연산자를 사용하여 const & then 연산자를 사용할 수도 있지만, 직접 연산자를 명시 적으로 사용하려는 경우 const &와 충돌하지만 실제로는 그렇지 않습니다. –

6

모호성은 캐스트 표현의 해석에서 비롯됩니다. 변환을 선택하면

는, 컴파일러는 먼저 static_cast 스타일의 캐스트를 고려하고 다음과 같습니다 초기화 해결하는 방법을 고려 : a가에 대한 사용자 정의 변환을 가지고로

std::list<unsigned_char> tmp(a); 

이 건설 모호을 std::list<unsigned char>unsigned charstd::list<unsigned char>에는 const std::list<unsigned char>&을 취하는 생성자와 (unsigned char을 승격 할 수있는 생성자)을 모두 갖는 생성자가 있습니다.

const std::list<unsigned_char>&로 전송이 초기화로 간주된다 std::list<unsigned_char>에 사용자 정의 변환 선택한 경우

이때
const std::list<unsigned_char>& tmp(a); 

, 상기 새로운 참조는 변환 결과에 직접 결합 할 수있다. unsigned char으로 사용자 정의 변환을 선택하여 std::list<unsigned char> 유형의 임시 개체를 만들어야하는 경우이 옵션은 이전 옵션보다 나쁜 변환 시퀀스를 만듭니다. 나는 다음에 예를 단순화했습니다

2

:

typedef unsigned int size_t; 

template <typename T> 
class List 
{ 
public: 
    typedef size_t size_type; 
    List (List const &); 
    List (size_type i, T const & = T()); 
}; 

typedef List<unsigned char> UCList; 

class MyClass 
{ 
public: 
    operator UCList const() const; 
    operator unsigned char() const; 
}; 

void foo() 
{ 
    MyClass mc; 
    (UCList)mc; 
} 

첫 번째 포인트는 표준의이 경우 C 스타일 캐스트가 더 적절한 C++ 스타일의 캐스트를 사용하도록 정의하고 있다는 점이다 static_cast.그래서 위의 캐스트가 동등에 :

static_cast<UCList> (mc); 

static_cast의 정의는 말한다 :

식 전자 명시 적 형태의 static_cast static_cast<T>(e) 사용하여 T 형으로 변환 할 수 있습니다 경우 선언 "T t(e);" 발명 된 임시 변수를 위해 잘 형성되어있다. t (8.5)

따라서 캐스트의 의미는 다음과 같다. 에 대한 두 개의 별도의 오버로드 확인 단계, 각 변환 연산자를 다음에 일어날 무엇

UCList (UCList const &)    #1 
UCList (size_type, T const & = T()); #2 

: 13.3.1.3에서

UCList tmp (mc); 

우리는 우리가 UCList에서 사용할 수있는 후보 생성자의 세트를 가져옵니다. # 1 변환

: UCList const &의 타겟 타입은 과부하 해상도는 다음의 변환 연산자 : 「 operator UCList const()」및 「 operator unsigned char()」사이에서 선택한다. unsigned char을 사용하려면 사용자 변환이 추가로 필요하므로이 오버로드 단계에서 실행 가능한 기능이 아닙니다. 따라서 과부하 해결이 성공하고 operator UCList const()을 사용합니다.

# 2로 변환 : 대상 유형이 size_t 인 경우. 기본 인수는 과부하 해결에 참여하지 않습니다. 과부하 해결은 다시 변환 연산자 "operator UCList const()"과 "operator unsigned char()"중에서 선택합니다. 이번에는 UCList에서 unsigned int으로 변환되지 않으므로 실행 가능한 기능이 아닙니다. unsigned charsize_t으로 승격 될 수 있으므로이 시간 오버로드 확인에 성공하고 "operator UCList const()"을 사용합니다.

그러나 이제 최상위 레벨에는 mc에서 UCList으로 성공적으로 변환 된 2 개의 별도의 독립적 인 과부하 해결 단계가 있습니다. 따라서 결과가 모호합니다.

마지막 점을 설명하기 위해,이 예제는 정상적인 과부하 해결의 경우와 다릅니다. 인수와 파라미터 유형 간의 관계 N :

void foo (char); 
void foo (short); 
void foo (int); 

void bar() { 
    int i; 
    foo (i); 
} 

여기 i=>char, i=>shorti=>int가 통상 1있다. 이들은 과부하 해결 방법으로 비교되며 과부하가 선택됩니다.

위의 경우 우리는 m : n 관계가 있습니다. 표준은 각 개별 인수와 모든 'n'매개 변수에 대해 선택하는 규칙에 대해 간략히 설명하고 있지만, 끝나는 곳은 다른 'm'인수를 사용하는 방법을 결정하는 방법을 지정하지 않습니다.

희망적이라고 생각하세요!

UPDATE : 여기 초기화 구문

2 종류가있다 :

UCList t1 (mc); 
UCList t2 = mc; 

'T1'는 직접 initialiation (13.3.1.3)와 모든 생성자이다는 과부하에 포함

세트. 이것은 하나 이상의 사용자 정의 변환을 갖는 것과 거의 같습니다. 변환 연산자 집합 집합이 있습니다. (즉, m : n). 객체의 복사본 초기화의 일부로서 8.5에 명시된 조건

: 구문 'T2'의 경우

다른 복사본 초기화 (13.3.1.4)와 규칙을 사용 클래스 유형의 경우 사용자 정의 변환을 호출하여 초기화 프로그램 표현식을 초기화중인 오브젝트 유형으로 변환 할 수 있습니다. 과부하 해상도는 사용자 정의 변환을 선택하는 데 사용됩니다을 입력하는 한, UCList이이 경우

를 호출하고, 그래서 즉,이 변환 연산자의 집합입니다 고려하는 오버로드. 우리는 UCList의 다른 생성자를 고려하지 않는다.

+0

새로운 개체 (복사본 구성)에 대한 직접 복사 생성 및 할당이 동일한 규칙으로 작동하지 않는다는 것이 궁금합니다. UCList t (mc); # 이것은 모호합니다. UCList mylist = mc; # 이것은 모호하지 않다. –

+0

놀라운 대답. 당신은 많은 시간 동안 투표를 받아야합니다. –

+0

"희망이 있습니다! _"(T) x는 T (x)와 같은 것을 깨닫기 전까지는 아무 의미가 없습니다. '! 그것은 단지 초기 디자인 실수 일뿐입니다. – curiousguy