2016-08-09 2 views
3

SFINAE를 사용하여 한 번에 여러 유형의 구조체 템플릿을 특수화하려고합니다.기본 템플릿을 건드리지 않고 SFINAE 부분 특수화 사용

#include <iostream> 

template <typename T, typename Enable = void> 
struct S { 
    void operator()() { 
     std::cout << "Instantiated generic case" << std::endl; 
    } 
}; 

template<typename T> 
using enabled_type = typename std::enable_if< 
         std::is_same<T, int>::value || 
         std::is_same<T, float>::value 
        >::type; 

template <typename T> 
struct S<T, enabled_type<T>> { 
    void operator()() { 
     std::cout << "Instantiated int/float case" << std::endl; 
    } 
}; 

int main() { 
    S<float>()(); 
    return 0; 
} 

내 문제는 내가 외부 헤더 전용 라이브러리의 일부로서, typename Enable = void을 추가 할 S 구조체의 기본 템플릿을 수정할 수 있다는 것입니다 : 나는 다음과 같은 작품 같은 것을 알고있다. 따라서 기본 템플릿은 다음과 같이 표시되어야합니다.

이 템플릿을 특수화하기 위해 SFINAE를 사용할 수있는 방법이 있습니까?

편집 : S 구조체는 외부 라이브러리의 코드에 의해 사용되는 주, 그래서 실제로 S을 전문으로해야 할 것이다 그것을 서브 클래스 수 없습니다. 또한 실제 코드는 훨씬 복잡하고 SFINAE에서이 간단한 예제 (나는 여러 유형의 모든 조합에 대해 특수화해야하는 여러 템플릿 매개 변수가 있음)보다 많은 이점을 얻을 것입니다.

+0

'T'의 실제 형태에 따라 다음과 같이 도움이 될 수 있습니다. https://stackoverflow.com/a/30991097/4326278 – bogdan

답변

2

난 당신에 대한 나쁜 소식이있다 : 당신이 원하는 것은 불가능하다. 기본 템플릿에 enable_if을 수행 할 목적으로 기본값이 void 인 추가 템플릿 매개 변수가없는 경우 가장 일반적인 의미로이를 수행 할 방법이 없습니다. 가장 가까운 것은 템플릿 클래스 자체의 구조체를 특수화하는 것입니다. 즉,

template <class T> 
struct foo {}; 

template <class T> 
struct S<foo<T>> {}; 

이 방법이 효과적입니다. 그러나 분명히 이것은 특성과 일치하는 경우 뭔가를 전문화하는 것과 동일한 유연성을 제공하지 못합니다.

귀하의 문제는 실제로 특성을 만족시키는 모든 유형에 대해 std::hash을 전문화하려는 문제와 동일합니다. 귀하의 문제와 마찬가지로 기본 클래스 템플릿 정의는 라이브러리 코드에서 변경 될 수 없으며 실제로 라이브러리 코드는 특정 상황에서 자동으로 hash의 전문화를 내부적으로 사용하므로 실제로 새 템플릿 클래스를 정의 할 수 없습니다.

여기에서 비슷한 질문을 볼 수 있습니다 : Specializing std::hash to derived classes. 클래스에서 상속하는 것은 특성으로 표현 될 수 있지만 템플릿 기반 클래스로 표현 될 수없는 좋은 예입니다. 꽤 지식이있는 C++ 사람들은 그 질문에 눈을 돌 렸습니다. 그리고 아무도 전문화를 자동으로 없애기위한 매크로를 작성하는 OP의 솔루션보다 더 나은 대답을 제공하지 못했습니다. 나는 그것이 불행히도 당신을위한 최고의 해결책이 될 것이라고 생각합니다.

다시 보았을 때 hash은 다른 경우에 최소한의 오버 헤드로이 사용 사례를 지원하기 위해 void로 기본 설정된 두 번째 템플릿 매개 변수로 선언되었을 것입니다.나는 내가 어딘가에 대한 토론을 보았다고 맹세 할 수도 있었지만 그것을 추적 할 수는 없었다. 도서관 코드의 경우 문제를 제기하여 변경하도록 요청할 수 있습니다. 그것은 변화가없는 것으로 보입니다 :

template <class T, class = void> 
struct S {}; 

template <> 
struct S<double> {}; 

이 유효합니다.

+0

설명에 감사드립니다. 매크로가 내 문제를 해결할 수있는 방법 인 것처럼 보이지만, 특성을 사용하여 전문화하는 흥미로운 일반적인 문제는 해결책이없는 것 같습니다. – ibab

2

평범한 구형 화로는 충분하지 않습니까?

struct S_int_or_float { 
    void operator()() { 
     std::cout << "Instantiated int/float case" << std::endl; 
    } 
}; 

template<> struct S<int>: S_int_or_float {}; 
template<> struct S<float>: S_int_or_float {}; 

편집 :

: 당신은 당신이 매개 변수의 조합을 제공해야 ... 그래서 그들 중 적어도 두 가지가 있다고 ... 우리가 그와 함께 무엇을 할 수 있는지 볼 수 있습니다 이 단지 SFINAE에 대한 추가 매개 변수가 될하지만 여전히 것처럼
struct ParentS { /* some implementation */ }; 

template <class First, class Second> 
struct S<First, Second, enable_if_t<trait_for_first_and_second<First, Second>::value, first_accepted_type_of_third_parameter> >: ParentS { }; 

template <class First, class Second> 
struct S<First, Second, enable_if_t<trait_for_first_and_second<First, Second>::value, second_accepted_type_of_third_parameter> >: ParentS { }; 

// ... 

그것은 좋지 않다 아니에요 지수 ...

+0

업데이트 된 질문 (및 초기 의심)에 따르면 float_or_int 항목 단지 예일뿐입니다. 실제 요점은 특성을 충족시키는 모든 유형의 구조체를 전문화하는 것이므로 질문에 대답하지 않습니다. –

+2

예, int/float 특수화는 그 예입니다. SFINAE에 대해 생각하기 시작한 것은 매크로를 사용하여 달성 할 수있는 것 이상으로 코드가 훨씬 단순해질 것이라는 것을 깨달았 기 때문입니다. 필자의 경우 여러 개의 템플릿 매개 변수가 필요하므로 전문적인 분석이 필요합니다. 이는 조합 적 분해가 약간 있음을 의미합니다. – ibab

+0

별도의 구조체를 사용하고 전문화 할 때 상속하면 많은 코드를 작성해야합니다. 이 방법을 사용하면 매크로 솔루션이 너무 나빠 보이지 않습니다. 고마워요! – ibab

관련 문제