2009-12-13 5 views
3

C++ 템플릿과 모호성 문제 :내가 같이 포인터 클래스의 부분 집합이

template <typename T> 
struct Pointer 
{ 
    Pointer(); 
    Pointer(T *const x); 
    Pointer(const Pointer &x); 
    template <typename t> 
    Pointer(const Pointer<t> &x); 

    operator T *() const; 
}; 
마지막 생성자의 목표는 서브 클래스의 Pointer, 또는이다 기본적으로 모든 종류의를 통과 할 수 있도록하는 것입니다

을 암시 적으로 T *으로 변환됩니다. 이 실제 규칙은 생성자의 정의에 의해서만 적용되며 컴파일러는 선언으로 혼자만 알아낼 수 없습니다. 내가 그것을 놓고 을 Pointer<Base>의 생성자에 전달하려고 시도하면 가능한 경로가 operator T *() 임에도 불구하고 컴파일 오류가 발생합니다.

위의 문제를 해결하는 동안 다른 문제가 발생합니다. 한 오버로드가 Pointer<UnrelatedClass>이고 다른 하나가 Pointer<BaseClass> 인 오버로드 된 함수가 있고 Pointer<SubClass>을 호출하려고하면 두 개의 오버로드 사이에 모호성이 생기므로 의도적으로 해당 오버로드가 호출됩니다. .

제안 사항? 질문 명시 적으로 생성자를 만들 수

+0

이 추가 템플릿 인수로 자본'U'를 사용하는 것이 훨씬 더 일반적입니다 : is_convertible는 다음과 같이 보인다. 소문자't'는 오타처럼 보입니다. – GManNickG

+0

암시 적 변환은 좋지 않습니다. 'operator T *()'대신'T * get()'을 사용하십시오. shared_ptr은 이와 같은 일을합니다. –

답변

6

치료법이 (대체 실패 오류가 아닙니다)

#include "boost/type_traits/is_convertible.hpp" 
#include "boost/utility/enable_if.hpp" 

template<typename T> 
class Pointer { 
    ... 
    template<typename U> 
    Pointer(const Pointer<U> &x, 
     typename boost::enable_if< 
     boost::is_convertible<U*,T*> 
     >::type* =0) 
    : ... 
    { 
    ... 
    } 
    ... 
}; 

U는 * T로 전환하는 경우 SFINAE라고 * enable_if는 무효화하기 위해 디폴트로 형식 정의 멤버 type있을 것이다. 그렇다면 모든 것이 좋습니다. U *가 T *로 변환 할 수없는 경우이 typedef 멤버가 누락되어 대체가 실패하고 생성자 템플리트가 무시됩니다.

변환 및 모호성 문제를 해결합니다. 주석에 대한 응답으로

:

typedef char one;   // sizeof == 1 per definition 
struct two {char c[2];}; // sizeof != 1 

template<typename T, typename U> 
class is_convertible { 
    static T source(); 
    static one sink(U); 
    static two sink(...); 
public: 
    static const bool value = sizeof(sink(source()))==1; 
}; 
+0

요점, 좋은 생각을 얻었다. 프로젝트는 현재 부스트를 사용하지 않습니다. 'is_convertible'이 어떻게 작동하는지 알고 싶습니다. – cvb

+0

예. 자유롭게 upvote.:) – sellibitze

+0

열 번 upvoted 것,하지만 난 등록되지 않았습니다 :) – cvb

0

시도, 예컨대이 : (다행스럽게도 필자는 충분히 명확했다)

template <typename t> 
explicit Pointer(const Pointer<t> &x); 

그리고/또는 제거 operator T *() const; -이 하나가 또한 모호성을 만들 것이라 생각합니다.

편집

확인 std::auto_ptr 인터페이스, 그리고 당신과 비교. 적어도 그들은 애매 모호함을 해결했습니다. 당신의 문제에 대한

+0

선언문에'explicilt'를 추가하면 같은 효과가 발생합니다. 컴파일 오류가 발생합니다 (2 개의 오버로드 중 어느 것도 모든 인수 유형을 변환 할 수 없습니다 ...). 캐스팅 오퍼레이터를 제거해도 문제가 해결되지는 않습니다 (어쨌든 클래스의 중요한 부분입니다). – cvb

+0

포인터를 사용하는 위치에 코드를 추가하고 컴파일 오류가 발생하는 위치와 오류를 추가하십시오 ( – Frunsi

+0

). 캐스팅 운영자가 여전히 (Alexey가 이미 지적한 것처럼) 모호함의 원인 일 수는 있지만, , 암시 적 변환을하는 것은 나쁜 생각입니다 : std :: auto_ptr은 그것을 추가하지 않았고, boost ptrs는 같은 이유로 (어떤 경우에는 ambuigity) 그것을 추가하지 않습니다. – Frunsi