2017-12-17 22 views
1

템플릿 클래스 C<T>AB으로 으로 인스턴스화하려는 템플릿 클래스가 있습니다. C<T>foo의 메소드를 가지며, 그 서명은 TA 또는 B으로 인스턴스화되었는지 여부에 따라 달라지기를 원합니다. 예를 들어, 다음 코드를 고려하십시오.SFINAE 및 매개 변수의 수

#include <iostream> 
#include <string> 

class A { 
public: 
    void message() { 
     std::cout << "message with no args" << std::endl; 
    } 
}; 

class B { 
public: 
    void message(int x) { 
     std::cout << "message with " << x << std::endl; 
    } 
}; 

template<typename T> 
class C { 
private: 
    T internal; 
public: 
    C(T& x) { 
     internal = x; 
    } 
    void call() { 
     internal.message(); 
    } 
    void call(int x) { 
     internal.message(x); 
    } 
}; 

int main(int argc, char* argv[]) { 
    A a; 
    B b; 
    C<A> ca(a); 
    C<B> cb(b); 
    ca.call(); 
    cb.call(42); 
// ca.call(42); ERROR HERE 
    return 0; 
} 

이것은 올바르게 실행됩니다. ca.call(42)A::message(int) 메서드가 없으므로 컴파일 오류가 발생합니다. 그러나 어떤 이유로 든 AA::message(int)이라는 메서드를 도입하면 코드에서 ca.call(42)을 호출하는 것을 허용 할 수 있습니다.

SFINAE 기술을 사용하면 을 선언 할 수 있습니다. 여기에서 T::call_type은 각각 의도 된 구체화 T에 대한 typedef가됩니다. 그러나이 경우에만 인수의 형식을 C::call 변경할 수 있습니다. 대신 (특히 매개 변수의 수) 의 T에 서명하고 싶습니다. 따라서 ca.call(42)이 에 A::message(int)이라는 방법이 있어도 유효한 호출이되는 것을 방지합니다.

이렇게 할 방법이 있습니까?

답변

1

SFINAE의 모든 기능을 알지 못합니다.하지만이 점에 대해 어떻게 생각합니까?

template < 
    typename = std::enable_if_t<std::is_same<std::decay_t<T>, A>::value>> 
void call() { 
    internal.message(); 
} 
template < 
    typename = std::enable_if_t<std::is_same<std::decay_t<T>, B>::value>> 
void call(int x) { 
    internal.message(x); 
} 

당신은 사용할 수 있습니다 == false 너무

template < 
    typename = std::enable_if_t<std::is_same<std::decay_t<T>, B>::value == false>> 
0

당신은 템플릿의 전문화와 함께이 작업을 수행 할 수 있습니다

// Main template used by every other type T. 
template<typename T> 
class C; // or some other implementation. 

// This gets used for T = A. 
template<> 
class C<A> { 
private: 
    A internal; 
public: 
    C(A& x) { 
     internal = x; 
    } 
    void call() { 
     internal.message(); 
    } 
}; 

// This gets used for T = B. 
template<> 
class C<B> { 
private: 
    B internal; 
public: 
    C(B& x) { 
     internal = x; 
    } 
    void call(int x) { 
     internal.message(x); 
    } 
}; 

를 당신은 몇 가지 일반적인 코드를 복제 할 필요가 마음에 들지 않으면, 당신은 모든 일반적인 것들로 기본 클래스를 가지고 그것으로부터 상속 할 수 있습니다 각 전문 분야에서.