2011-04-19 7 views
4

파생 된 모든 유형 및 템플릿 생성자에 대해 생성자를 정의 할 수 있습니까? 나는 내 문제를 설명하기 위해이 테스트 케이스를 작성했습니다 :생성자 우선 순위 변경

#include <iostream> 


class Variant; 
class CustomVariant; 


class Variant 
{ 
public: 
    Variant(void) 
     {} 


    Variant(const Variant&) 
     { 
      std::cout << "ctor" << std::endl; 
     } 


    Variant(const CustomVariant&) 
     { 
      std::cout << "custom" << std::endl; 
     } 


    template<typename T> 
    Variant(const T&) 
     { 
      std::cout << "template" << std::endl; 
     } 
}; 


class CustomVariant : public Variant 
{ 
}; 


class DerivedVariantA : public CustomVariant 
{ 
}; 


class DerivedVariantB : public CustomVariant 
{ 
}; 


int main(void) 
{ 

    DerivedVariantB dvb; 

    Variant v(dvb); 
    // expcected output: "custom" instead of "template" 

} 

답변

6
template <typename T> Variant(const T&) // (a) 
Variant(const CustomVariant&)   // (b) 

없음 변환이 호출 할 필요가 없습니다 (A)을; 인수 유형 DerivedVariantB은 정확히 일치합니다 (T = DerivedVariantB).

(b)을 호출하려면 파생 - 기준 변환이 필요합니다. 따라서 (a)(b)보다 더 일치합니다. 당신이 유형 CustomVariant의 인수와 함께 생성자를 호출하면

는 모두 생성자는 다른 모든 동일한이다하는 nontemplate 템플릿 선호하기 때문에 그렇게 이 (b)에을 선택 정확히 일치입니다.

당신은 Tstd::enable_if를 사용하여 Variant에서 파생 된 템플릿의 사용을 억제 할 수

template<typename T> 
Variant(const T&, 
     typename std::enable_if< 
        !std::is_base_of<Variant, T>::value, void* 
       >::type = 0) 
{ 
    std::cout << "template" << std::endl; 
} 

이것은 TVariant에서 파생 될 때 인스턴스화되지 템플릿을 만드는을, 그래서 오버로드 확인하는 동안 사용할 수 없습니다 . enable_ifis_base_of은 C++ 0x에서 C++의 새로운 기능으로 컴파일러와 표준 라이브러리가이를 지원할 수 있습니다. 그렇지 않은 경우 C++ TR1 또는 Boost.TypeTraits에서도 찾을 수 있습니다.

+0

예, 표준에서 정의한 규칙입니다. 문제는 해결 방법이 있습니까? :) – cytrinox

+0

있습니다. 방금 예를 들어 답을 업데이트했습니다. –

+0

와우. 그것은 SFINAE 때문에 작동합니다 (값은 Variant에서 파생 된 유형에 대해 정의되지 않았습니다)? – cytrinox

0

아니요, 클래스에서 사용 가능한 생성자 목록 중에 DerivedVariantB 유형의 인스턴스를 인수로 사용하는 생성자가 없습니다. 따라서 생성 된 템플릿이 호출되고 있습니다.

class DerivedVariantB ; // Forward Declaration 

class Variant 
{ 
    public: 
    // ... 

    Variant(const DerivedVariantB &obj) 
    { 
     std::cout << "\n DerivedVariantB \n"; 
    } 
}; 

지금, 그것은 유형 DerivedVariantB 대신 중 하나를 생성 된 템플릿의 참조를 취하는 생성자를 호출 할 수 있습니다.