2014-10-30 2 views
6

나는 다음과 같은 템플릿 개체가 :std :: enable_if를 사용하여 템플릿 유형에 따라 생성자를 사용하거나 사용하지 않도록 설정하는 방법은 무엇입니까?

template< typename type_1, typename type_2 > struct result 
{ 
    // I want to enable these two constructors only if type_1 != type_2 
    result(type_1 f) : foo{f} {} 
    result(type_2 b) : bar{b} {} 

    // I want to enable this constructor only if type_1 == type_2 
    result(type_1 f, type_2 b) : foo{f}, bar{b} {} 

    // Other member functions removed. 

    type_1 foo; 
    type_2 bar; 
}; 

가 어떻게 필요에 따라 활성화 또는 생성자를 사용하지 않도록 std::enable_if을 사용합니까를?

예 :

이 하나가있는 것입니다 만 처음 두 생성자 :

result<string,int> // type_1 != type_2 

이 하나는 세 번째 생성자 것 :

result<int,int> // type_1 == type_2 

답변

5

This 일 것 같다,하지만 내가 최적의 방법인지 확실하지 않습니다.

생성자에 기본값으로 새로운 템플릿 매개 변수도 읽고

#include <type_traits> 

template< typename type_1, typename type_2 > 
struct result 
{ 
    // I want to enable these two constructors only if type_1 != type_2 
    template<typename T1 = type_1, typename T2 = type_2> 
    result(type_1 f, 
      typename std::enable_if<!std::is_same<T1, T2>::value>::type * = nullptr) 
     : foo{f} {} 
    template<typename T1 = type_1, typename T2 = type_2> 
    result(type_2 b, 
      typename std::enable_if<!std::is_same<T1, T2>::value, int >::type * = nullptr) 
     : bar{b} {}          /*  ^^^ need this to avoid duplicated signature error with above one*/ 

    // I want to enable this constructor only if type_1 == type_2 
    template<typename T1 = type_1, typename T2 = type_2> 
    result(type_1 f, type_2 b, 
      typename std::enable_if<std::is_same<T1, T2>::value>::type * = nullptr) 
     : foo{f}, bar{b} {} 

    type_1 foo; 
    type_2 bar; 
}; 

int main() 
{ 
    result<int, double> r(1); 
    result<int, double> r2(1.0); 

    result<int, int> r3(1, 2); 

    // disbaled 
    //result<int, double> r4(1, 2.0); 
    //result<int, int> r5(1); 
} 

SFINAE

을 사용하려면 다음 Select class constructor using enable_if

4

기본 템플릿은 mistmatched 유형에 대한 전문화 역할을 할 수 있습니다. 이것은 @ BryanChen의 대답과 유사

template <typename type_1, typename type_2> 
struct result 
{ 
    result(type_1 f) : foo{f} {} 
    result(type_2 b) : bar{b} {} 

    type_1 foo; 
    type_2 bar; 
}; 

template <typename type> 
struct result<type, type> 
{ 
    result(type f, type b) : foo{f}, bar{b} {} 

    type foo; 
    type bar; 
}; 
+1

'result' 객체에 표시된 멤버 함수가 많아서 전문화하면 많은 코드 중복이 발생할 수 있습니다. –

+1

@DrTwox 그런 다음 브라이언의 솔루션을 사용하십시오. 불행히도 나는 현재 어떤 대안도 모르고있다. – 0x499602D2

+1

@DrTwox 하나의 클래스에 모든 공통 코드를 넣고 다른 클래스에 특수 코드를 넣으면 반복을 피하기 위해 상속을 사용할 수 있습니다. 이것은 일반적인 해결책입니다. 상황에 따라 CRTP를 포함한 여러 가지 방법으로이 작업을 수행 할 수 있습니다. 예를 들어, 기본 클래스에 생성자 (및 데이터 멤버)를 둘 수 있습니다.이 클래스는 두 경우 모두에 대해 같거나 비슷하지 않으며 파생 클래스에서 상속 된 생성자 (C++ 11)를 사용합니다. 또는 반대로, 파생 클래스를 기본 클래스의 모든 공통 코드와 함께 전문화하십시오. –

2

하지만, 청소기 IMO : 당신은 모호함 해상도를 개선하기 위해 상속을 사용하여 생성자의 템플릿 인수에 enable_if의 이동 : 일치하는 유형의 당신은 부분적으로 전문화 할 수 있습니다.

#include <iostream> 
#include <string> 
#include <type_traits> 

using namespace std; 

template <int N> 
class Disambiguator; 

template<> 
class Disambiguator<0>{}; 

template <int N> 
class Disambiguator : public Disambiguator<N-1>{}; 

using Disambiguate = Disambiguator<100>; 

template< typename type_1, typename type_2 > struct result 
{ 
    template <typename T, typename U> 
    using IsSame = typename enable_if<is_same<T, U>::value>::type; 

    template <typename T, typename U> 
    using IsNotSame = typename enable_if<!is_same<T, U>::value>::type; 

    template <typename T = type_1, typename U = type_2, typename = IsNotSame<T,U>> 
    result(type_1 f, Disambiguator<0>) : foo{f} {cout<<"NotSameType"<<endl;} 

    template <typename T = type_1, typename U = type_2, typename = IsNotSame<T,U>> 
    result(type_2 b, Disambiguator<1>) : bar{b} {cout<<"NotSameType"<<endl;} 

    // I want to enable this constructor only if type_1 == type_2 
    template <typename T = type_1, typename U = type_2, typename = IsSame<T,U>> 
    result(type_1 f, type_2 b) : foo{f}, bar{b} {cout<<"SameType"<<endl;} 

    // Other member functions removed. 

    type_1 foo; 
    type_2 bar; 
}; 


int main() 
{ 
    result<float, int> c(1.0, Disambiguate{}); 
    result<float, int> i(0, Disambiguate{}); 

    result<int, int> j(0, 0); 

    result<string, int> s("abc", Disambiguate{}); 
    result<string, int> si(0, Disambiguate{}); 

    return 0; 
} 

편집 : 당신은 Xeo의 오버로드 확인 아이디어 here @ 읽을 수 있습니다. 이것이 위 코드에서 사용한 것입니다.

관련 문제