2013-08-06 3 views
2

SFINAE를 여러 번 성공적으로 사용했습니다. 클래스가 함수를 제공하는지 여부를 감지하는 것은 문제가되지 않습니다. 현재의 문제는 his problem의 반대편 인 것 같습니다! 대신이 파생 된 메서드를 검색하므로 클래스의 메서드 만 검색하는 것이 좋습니다. 이 방법이 템플릿이라는 사실과 관련이있는 것 같습니다.SFINAE를 사용하여 템플릿 클래스 멤버 함수를 검색 할 수 있습니까?

클래스 템플릿 방법을 감지 할 수 있습니까? 해를 끼치 지 않는 유형의 템플릿을 인스턴스화하려고 시도했지만 운이 없습니다.

struct A { template<class T> void Func(T) {}; }; 
struct B :A {}; 

template< class T > 
struct CheckForFunc 
{ 
    typedef char(&YesType)[1]; 
    typedef char(&NoType)[2]; 
    template< class U, void (U::*)(int) > struct Sfinae; 

    template< class T2 > static YesType Test(Sfinae<T2,&T2::Func>*); 
    template< class T2 > static NoType Test(...); 
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType); 
}; 

int main(int argc, char* argv[]) 
{ 
    // gives "1" 
    std::cout << "Value A=" << CheckForFunc<A>::value << std::endl; 
    // doesn't compile! 
    std::cout << "Value B=" << CheckForFunc<B>::value << std::endl; 
    return 0; 
} 

오류 메시지 :이 SFINAE은 그냥 유도로, 템플릿 방법과 매우 잘 작동

error: ‘&A::Func’ is not a valid template argument for type ‘void (B::*)(int)’ because it is of type ‘void (A::*)(int)’ 

주의! 나쁜 것은 그것이 잘못 발견하지 않는다는 것입니다. 컴파일이 실패합니다.

'샘플'유형 (여기에서는 int)을 사용하지 않고 SFINAE 테스트를 작성하는 방법은 무엇입니까?

편집 : 죄송합니다, C++ 03! 그리고 LLVM은 VS2008도 GCC와 QNX (내일은 봐야 할 버전)가 아니 었습니다.

편집 2 : Coliru에 대해 몰랐습니다! 매우 시원하고 여기는 error입니다!

+1

그냥 사용할 이유 0 '시험 (보이드 (T2 : : *) (int) = nullptr)'sizeof (테스트 ())'? –

+1

[귀하의 코드는 clang ++을 사용하여 컴파일됩니다.] (http://coliru.stacked-crooked.com/view?id=869eb009d893d56f344c9c7c09356b5d-e223fd4a885a77b520bbfe69dda8fb91). 나는 이상한 것을 발견한다! 나는 그것이 clang의 버그라고 생각합니다! – Nawaz

+0

기본 인수를 사용하는 흥미로운 생각. nullptr C++ 11입니까? – Borph

답변

3

이 문제는 올바르게 해결 된 클래스 템플릿과 관련이 없지만 구성원 주소 표현의 이상한 특징입니다. 종류로, 특히 :

struct base { void foo(); }; 
struct derived : base {}; 

표현 &derived::foo는 또는 직관적되지 않을 수도 타입 void (base::*)()이다.

멤버 함수 템플릿의 존재를 확인하는 테스트에서 나는 대답이 없습니다. 템플릿의 주소를 가져올 수는 없지만 가짜 형식을 만들어 해당 유형의 함수를 호출 해보십시오. 클래스가 그 타입을 취하는 함수를 가질 수있는 유일한 방법은 함수 자체가 템플릿 인 경우입니다. 평가되지 않은 표현식의 내부에서 이것을 사용하여 odr- 형식의 템플릿 함수를 사용하지 않아도됩니다.

+1

"& derived :: foo 표현식은 void (base :: *)()"유형입니다. 올바른 내용이지만 여기서는 문제가 아닌 것 같습니다. OP는 상속되지 않는 멤버 함수 템플릿을 검색하려고합니다 (OP를 이해하는 한). '& A :: Func' 표현식은 아직 [over.over] 타입이 없지만'void (A :: *) (int)'와'void (B :: *) (int)'와 일치합니다. – dyp

+0

@DyP :'& A :: Func'는 템플릿의 포인터에서 멤버로 포인터에서 멤버로의 변환을 필요로하기 때문에 템플릿에서'void (B :: *) (int)'와 일치 할 수 없습니다. 파생되지 않은 템플릿 인수에 대한 유효한 변환 중 하나가 아닌 파생됩니다. 당신은'& A :: Func'가 과부하 해결 후보의 집합 인 부분을 건너 뛰었 습니다만, 어떤 타입은'T' (즉' A '는 전체 집합에 고정되어 있습니다. –

+0

예, 처음에는 생각했지만 [over.over]에 주석이 있습니다. "[참고 : 즉, 함수가 멤버 인 클래스는 member-function에 대한 포인터와 일치 유형 "-end note]" – dyp

2

나는이 수정을 사용 :

입니다
Sfinae<T2, decltype(std::declval<T2>().Func(0))> 

, 표현 obj.Func(0)유형을 사용하고 Sfinae 클래스 템플릿에 전달합니다.

다음은 수정과 전체 코드입니다 :

#include <iostream> 
#include <utility> 

struct A { template<class T> void Func(T) {}; }; 

struct B : A {}; 

struct C {}; 

template< class T > 
struct CheckForFunc 
{ 
    typedef char(&YesType)[1]; 
    typedef char(&NoType)[2]; 
    template< class, class > struct Sfinae; 

    template< class T2 > static YesType Test(Sfinae<T2, decltype(std::declval<T2>().Func(0))> *); 
    template< class T2 > static NoType Test(...); 
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType); 
}; 

int main(int argc, char* argv[]) 
{ 
    std::cout << "Value A=" << CheckForFunc<A>::value << std::endl; 
    std::cout << "Value B=" << CheckForFunc<B>::value << std::endl; 
    std::cout << "Value C=" << CheckForFunc<C>::value << std::endl; 
    return 0; 
} 

출력 :

Value A=1 
Value B=1 
Value C=0 

나는이 데모에 클래스 C을 추가했다.

Online Demo.당신이 멤버 함수 템플릿이 있어야 정확한 템플릿 매개 변수를 알고 있다면 :-)

+0

OP는 출력 값 'Value B = 0'을 원한다고 생각합니다. "파생 된 메소드를 감지하는 대신 클래스의 메소드 만 감지하는 편이 좋습니다 – dyp

+1

@DyP : 그건 나에게 이해가되지 않습니다 그게 가능하다고 생각합니다.) 일단 상속받은 기본 메소드가 파생 클래스의 클래스 메소드가되기 때문입니다. – Nawaz

+1

David Rodríguez의 답변을 참조하십시오. 오버로드되지 않는 함수 (및 템플릿이 아닌)의 경우,'& B :: Func' 식의 형식은'void (A :: *) (int)'입니다. 하지만 OP가 왜 그 수 표를 필요로하는지 알지 못합니다. – dyp

0

이 작동 : 는

#include <iostream> 
#include <type_traits> 

struct A { template<class T> void Func(T) {} }; 
struct B :A {}; 

template< class T > 
struct CheckForFunc 
{ 
    typedef char(&YesType)[1]; 
    typedef char(&NoType)[2]; 

    template< class T2 > static YesType Test(
     typename std::enable_if< 
      std::is_same<void (T::*)(int), decltype(&T2::template Func<int>)>{}, 
      int 
     >::type); 
    template< class T2 > static NoType Test(...); 
    static const bool value = sizeof(Test<T>(0))==sizeof(YesType); 
}; 

int main(int argc, char* argv[]) 
{ 
    // gives "1" 
    std::cout << "Value A=" << CheckForFunc<A>::value << std::endl; 
    // doesn't compile! 
    std::cout << "Value B=" << CheckForFunc<B>::value << std::endl; 
    return 0; 
} 
(는 C++ 03 기능에 의해 대체 될 수있는 몇 가지 C++ 11 기능을 사용합니다)

출력 :

값 A = 1
값 B =

관련 문제