2010-08-12 4 views
2

클래스에 기능이 있는지 확인하기 위해 SFINAE 테스트를 받았습니다. 테스트가 제대로 작동하지만 if 문에서 사용할 때 컴파일러 오류가 발생합니다. 내가 할제어 흐름 명령문에서 SFINAE 테스트를 사용할 수 있습니까?

//SFINAE test for setInstanceKey() 
template <typename K> 
class HasSetInstanceKey 
{ 
    template <typename C> 
    static char test(typeof(&C::setInstanceKey)); 

    template <typename C> 
    static long test(...); 

public: 
    enum { value = 1 == sizeof(test<K>(0)) }; 
}; 

는 다음 다른 절을 실행한다하더라도 두 번째 줄에 "오류 '클래스 노드' 'setInstanceKey'라는 이름의 회원이 없습니다."

if (0 != HasSetInstanceKey<T>::value) 
    instance->setInstanceKey(instanceKey); 
else 
    ... 

이 방법을 사용할 수 있습니까?

감사합니다.

+1

Ew, 동등성 테스트의 왼쪽에있는 상수. :) – GManNickG

+0

나는 그것을 여기에서 집어 들었다. 그들은 요다 조건이라고합니다. http://stackoverflow.com/questions/2349378/new-programming-jargon-you-coined/2430307#2430307 – Kevin

+1

@ 케빈 : 이전에 그랬다는 뜻인가요? D : 빨리, 되돌리기! – GManNickG

답변

3

if 분기가 입력되지 않았다고해서 분기 내의 코드가 유효하지 않을 수 있다는 것을 의미하지는 않습니다. (생각해 볼 수있는 또 다른 방법은 최적화에 대해서는 보장 할 수 없지만, 코드는 데드 브렌치 최적화에만 유효합니다.)

분기를 함수로 옮기는 것입니다. 일반적으로이 같은 프레임 워크를 가지고 :

// holds some integral constant 
template <typename T, T V> 
struct integral_constant 
{ 
    static const T value = V; 
}; 

// holds a boolean constant 
template <bool V> 
struct bool_type : integral_constant<bool, V> 
{}; 

typedef bool_type<true> true_type; // a true boolean constant 
typedef bool_type<false> false_type; // a false boolean constant 

typedef const true_type& true_tag; // tag a function as the true variant 
typedef const false_type& false_tag; // tag a function as the false variant 

그런 다음이 같은 :

namespace detail 
{ 
    // implementation 
    template <typename K> 
    class HasSetInstanceKey 
    { 
     // note, using char and long doesn't necessarily guarantee 
     // they each have a unique size. do this instead: 
     typedef char yes[1]; 
     typedef char no[2]; // these must have different sizes 

     template <typename C> 
     static yes& test(typeof(&C::setInstanceKey)); 

     template <typename C> 
     static no& test(...); 

    public: 
     // check against size of yes result 
     static const bool value = sizeof(test<K>(0)) == sizeof(yes); 
    }; 
} 

template <typename K> 
struct HasSetInstanceKey : // delegate to implementation, take result and 
    bool_type<detail::HasSetInstanceKey<K>::value> // inherit from the 
                // appropriate bool_type 
{}; 
:

namespace detail 
{ 
    template <typename T, typename KeyType> 
    void foo(T* instance, const KeyType& instanceKey, true_tag) 
    { 
     // we are in the true variant, so our meta-function's value was true 
     // therefore, instance has the ability to do setInstanceKey 
     instance->setInstanceKey(instanceKey); 
    } 

    template <typename T, typename KeyType> 
    void foo(T*, const KeyType&, false_tag) 
    { 
     // we are in the false variant, so our meta-function's value was false 
     // therefore, instance does not have the right capabilities, 
     // so do nothing 
    } 
} 

// interface, forwards to correct implementation function 
template <typename T, typename KeyType> 
void foo(T* instance, const KeyType& instanceKey) 
{ 
    // pass instance, but to the overloaded foo 
    // that accepts the right boolean result 
    detail::foo(instance, instanceKey, // plug the value into a bool_type, 
       bool_type<HasSetInstanceKey<T>::value>()); // and instantiate it 
       // will either go into the true_tag or false_tag 
} 

그것은 메타 기능을 가지고 좋은 연습의 사용을 용이하게하기 위해, 올바른 bool_type에서 상속

그러면 다음과 같이됩니다.

template <typename T, typename KeyType> 
void foo(T* instance, const KeyType& instanceKey) 
{ 
    // because it inherits from bool_type, it can be implicitly 
    // converted into either true_tag or false_tag 
    detail::foo(instance, instanceKey, HasSetInstanceKey<T>()); 
} 
+0

잘 작동하지 않습니다. g ++는 "void foo (const T & pX, true_tag)"와 "void foo (const T &, false_tag)"의 차이점을 알 수 없습니다. 이전에 정의 된 오류가 나타납니다. – Kevin

+0

@Kevin :'true_tag'는'false_tag'와 같은 타입이 아니라면 불가능합니다. 똑같은 잘못 입력 했습니까? – GManNickG

+0

@GMan : 각각의 foo() 위의 줄에 "template "을 추가하면 "이전에 정의 된"오류가 수정됩니다. 만약 내가 이것을 테스트 할 때 작동하도록 기대해야하는지 확신하지 못한다. 여전히 다른 에러를 디버깅 중이다. – Kevin

관련 문제