2012-06-15 1 views
1

죄송합니다. 비슷한 질문이 많지만 아무도이 문제를 해결하지 못하는 것 같습니다. 그들은 모두 조금 다릅니다.C++ 단일 생성자 템플릿 전문화

그래서 달성하고자하는 것 : 템플릿 클래스 X<T>을 고려하십시오. 이제는 여분의 생성자가 해당 템플릿의 특정 인스턴스에 대해 내포하고 싶습니다. X<T*> 포인터에 대해 말하면됩니다. 나는 X<T*>에 대한 전체 템플릿 명세를 만들고 싶지 않습니다. 왜냐하면 X<T*>은 일반 템플릿과 정확히 일치해야하기 때문에 (템플릿은 거대합니다. 따라서 복사 붙여 넣기는 상당한 코드 중복 냄새가 날 것입니다), 단지 추가 생성자가 있습니다. X<T*>X<T>에서 상속 받고 싶지는 않습니다. 왜냐하면이 두 가지 사이에 하위 유형 관계를 설정하고 싶지 않기 때문입니다. 이것이 가능합니까? 나는 이것을 이렇게 시도했다 :

template<T> class X{}; 

template<T> X<T*>::X(int i){...} 

그러나 그것은 컴파일하지 않는다. 어떻게 든 가능합니까?

+0

나는 이것이 가능하다고 생각하지 않는다. 내가 할 수있는 유일한 두 가지 방법은 당신이 그것을하고 싶지 않은 두 가지 방법이다. –

+0

당신은 항상 정적 팩토리 메소드 나 도우미 클래스에 의지 할 수 있습니다. 또는 최후의 수단으로,'X 인스턴스 (* ptr); – Rook

+0

에는 정적 팩토리를 암시 적 변환으로 사용할 수있는 방법이 있습니까? – gexicide

답변

5

당신은 SFINAE를 사용하여,이 같은 작업을 수행 할 수 있습니다

#include <iostream> 
#include <type_traits> 

template<class T> class X{ 
public: 
    X(int i) { 
     init(); 
    } 
private: 
    template<class U = T> 
    typename std::enable_if<std::is_pointer<U>::value>::type init() { 
     std::cout << "It's a pointer!\n"; 
    } 

    template<class U = T> 
    typename std::enable_if<!std::is_pointer<U>::value>::type init() { 
     std::cout << "It's not a pointer!\n"; 
    } 
}; 

int main() { 
    X<int> a(1); 
    X<int*> b(2); 
} 

출력한다 :

It's not a pointer! 
It's a pointer! 

당신은 생성자를 오버로드하지 않는,하지만 당신은 당신이 원하는 것을 달성하고 있습니다.

이 코드를 사용하려면 C++ 11이 필요합니다.

편집 : 여전히 이전과 동일 출력

#include <iostream> 
#include <type_traits> 

template<class T> class X{ 
public: 
    template<class U = T, class enabler = typename std::enable_if<std::is_pointer<U>::value, T>::type> 
    X(int i) { 
     std::cout << "It's a pointer!\n"; 
    } 

    template<class U = T, class enabler = typename std::enable_if<!std::is_pointer<U>::value, T*>::type> 
    X() { 
     std::cout << "It's not a pointer!\n"; 
    } 
}; 

int main() { 
    X<int> a; 
    X<int*> b(2); 
} 

을 : 좋아,이 코드는 당신이 원하는 것을 정확히 않습니다. 이것은 꽤 좋은 디자인이 아닙니다. 템플릿 인자에 의존하는 생성자를 갖는 것은 이상합니다. 이 코드는 문제를 해결합니다.

+0

'enable_if'가 작동하려면'#include '이 필요합니다. – Alex

+0

@Vash 감사합니다. 다음을 포함합니다 : D. – mfontanini

+0

'템플릿 '의 의미는 무엇입니까? 'template '와 같은 다른 것들도 사용할 수 있습니까? – gexicide

0

다음은 부스트를 사용하지만 C++을 필요로하지 않는 솔루션입니다. 두 경우 모두 X에는 단일 인수를 사용하는 생성자가 있습니다. T이 포인터 인 경우 예상되는 인수는 int입니다. T이 포인터가 아닌 경우 인수는 호출자가 액세스 할 수없는 유형입니다.

#include <boost/type_traits.hpp> 

template < typename T > 
class X 
{ 
private: 
    // Declare a private type that will be used to prevent a single-argument 
    // constructor from being callable when T is not a pointer. 
    struct T_must_be_a_pointer; 
public: 
    // Branch at compile-time based on T: 
    // - If T is a pointer, then declare the X(int) constructor. 
    // - If T is not a pointer, then declare X(T_must_be_a_pointer) constructor. 
    explicit X(typename boost::mpl::if_< boost::is_pointer<T>, 
             int, 
             T_must_be_a_pointer >::type i) 
    {} 
}; 

int main() { 
    X<int> a(); 
    // Next line will fail to compile: 
    // X<int> b(1); 
    X<int*> c(2); 
    return 0; 
}