2017-01-16 14 views
5

std::enable_if을 C++ 11에서보다 잘 이해하려고하고 최소 예제를 작성하려고했습니다. 클래스가 A이고 멤버 함수가 void foo()이고 다른 클래스 템플릿의 유형 T을 기반으로 구현합니다.
아래 코드는 원하는 결과를 제공하지만 아직 완전히 이해하지 못했습니다. V2 버전이 작동하지만 V1이 아닌 이유는 무엇입니까? "중복"유형 인 U이 필요한 이유는 무엇입니까?enable_if : void 멤버 함수에 대한 최소한의 예제입니다.

#include <iostream> 
#include <type_traits> 

template <typename T> 
class A { 

    public: 

     A(T x) : a_(x) {} 

     // Enable this function if T == int 
     /* V1 */ // template <   typename std::enable_if<std::is_same<T,int>::value,int>::type = 0> 
     /* V2 */ template <typename U=T, typename std::enable_if<std::is_same<U,int>::value,int>::type = 0> 
     void foo() { std::cout << "\nINT: " << a_ << "\n"; } 

     // Enable this function if T == double 
     template <typename U=T, typename std::enable_if<std::is_same<U,double>::value,int>::type = 0> 
     void foo() { std::cout << "\nDOUBLE: " << a_ << "\n"; } 

    private: 

     T a_; 

}; 

int main() { 
    A<int> aInt(1); aInt.foo(); 
    A<double> aDouble(3.14); aDouble.foo(); 
    return 0; 
} 

원하는 결과를 달성하기위한 더 나은 방법이, 즉 클래스 템플릿 파라미터에 기초 void foo() 기능을 갖는 다른 구현에 대한?

+0

당신의 예제는'enable_if'를 적절하게 사용하지 않습니다. 간단한 오버로드로 문제가 해결됩니다. 'enable_if'는 주로 * 추론 된 * 템플릿 매개 변수에 유용합니다. –

+0

'std :: enable_if '를 사용하면 추론 된 * 부동 소수점 유형을, 예를 들어, * integral * 유형에서 분리하는 데 적합합니다. 이 두 가지 유형은 오버로드에 더 적합합니다 *. – WhozCraig

+0

@KerrekSB @WhozCraig이 특별한 경우 어떻게하면 과부하가 걸릴까요? 클래스 외 정의'void A :: foo() {}'와'void A :: foo() {}'를 사용하면? 내 의도는 최종 코드는 필요한 함수의 버전만을 포함한다는 것입니다 (즉, 함수가 호출되지 않는다면'A :: foo()'는 사용되지 않습니다) – untergam

답변

2

나는이 질문에 완전히 대답하지 않을 것이지만, 당신에게 더 많은 아이디어와 당신이 사용할 수있는 방법에 대한 이해를 줄 수 있음을 알고 있습니다. std::enable_if.

당신이 한 다음과 동일한 기능으로 foo는 멤버 함수를 대체 할 수 :

template<typename U=T> typename std::enable_if<std::is_same<U,int>::value>::type 
foo(){ /* enabled when T is type int */ } 

template<typename U=T> typename std::enable_if<std::is_same<U,double>::value>::type 
foo(){ /* enabled when T is type double */ } 

A가 다시 동안 어떻게 enable_if 작품이 꽤 좋은 이해를 얻었지만, 슬프게도 내가 잊어 버린 그 복잡한의 대부분 그것을 사용하는 실제적인 방법을 기억하십시오.

+0

'std :: enable_if <>'에 이미 포함되어 있기 때문에 함수 앞에'void'도 제거해야한다고 생각합니다. 그러나이 입력에 대한 thx는 내가 무슨 일이 일어나고 있는지 이해하는 데 한 걸음 더 가까이 다가 갈 수 있도록 도와주었습니다. 이것이 컴파일 타임 다형성을 달성하는 합법적 인 방법이라고 말씀해 주시겠습니까? – untergam

+0

@untergam 으악, 잘 잡아라! 나는 그것을 지금 편집 할 것이다.나는 그것이 일을하는 합법적 인 방법이라고 생각한다. 나는 그것을 할 수있는 더 좋은 방법이 있는지 확실하지 않다. –

0

첫 번째 질문은 다음과 같습니다. V1이 작동하지 않는 이유는 무엇입니까? SFINAE는 과부하 해결에만 적용됩니다. 그러나 V1에서는 유형 A가 인스턴스화 된 지점에서 오류가 발생합니다. 과부하 해결 foo()보다 훨씬 앞서야합니다.

가능한 구현이 많이 있다고 가정합니다. 문제의 실제 사례에 따라 가장 적절합니다. 일반적인 접근법은 다른 템플릿 유형에 따라 다른 부분을 도우미 클래스로 연기하는 것입니다. A

A의 나머지 부분은 일반적인 방법으로 한 번만 선언 할 수
template <typename T> 
class A_Helper; 

template <> 
class A_Helper<int> { 
public: 
    static void foo(int value){ 
     std::cout << "INT: " << value << std::endl; 
    } 
}; 

template <> 
class A_Helper<double> { 
public: 
    static void foo(double value){ 
     std::cout << "DOUBLE: " << value << std::endl; 
    } 
}; 

template <typename T> 
class A { 
public: 

    A(T a) : a_(a) 
    {} 

    void foo(){ 
     A_Helper<T>::foo(a_); 
    } 

private: 
    T a_; 
}; 

- 도우미로 연기되어 다른 부분 만. 귀하의 요구 사항에 따라 다양한 변형이있을 수 있습니다 ...

+0

답장을 보내 주셔서 감사합니다. @j_kubik. 템플릿이있는 도우미 클래스를 사용하는이 솔루션이 어떻게 작동하는지 알지만이 코드는 필자가 처음부터 피하려고했던 코드 팽창의 일종입니다. 나는 최소한의 버전을'enable_if' 또는 적어도 비슷한 구문으로 선호한다. – untergam