SFINAE - Próba określenia, czy typ szablonu ma funkcję składową z typem powrotu „zmienna”
Problemy z SFINAE. Muszę być w stanie określić, czy typ ma operatora funkcji-zdefiniowanej niezależnie od typu zwracanego. Poniżej następuje przykład.
Ta klasa w testerze. Definiuje operator -> () z typem powrotu X *. Nie będę więc wiedział, gdzie „X” ma zakodować go wszędzie.
<code>template <class X> class PointerX { ... X* operator->() const; ... } </code>
Ta klasa próbuje określić, czy przekazany w T ma zdefiniowany operator metody->; niezależnie od typu operatora-> powrotu.
<code>template<typename T> struct HasOperatorMemberAccessor { template <typename R, typename C> static R GetReturnType( R ( C::*)()const); template<typename U, typename R, R(U::*)()const> struct SFINAE{}; template<typename U> static char Test(SFINAE<U, decltype( GetReturnType(&U::operator->)), &U::operator-> >*); template<typename U> static uint Test(...); static const bool value = sizeof(Test<T>(0)) == sizeof(char); }; </code>
Ta klasa jest dokładnie taka sama jak powyżej, z tym wyjątkiem, że typ operator-> return musi mieć wartość „Object”.
<code>template<typename T> struct HasOperatorMemberAccessorOBJECT { template <typename R, typename C> static R GetReturnType( R ( C::*)()const); template<typename U, typename R, R(U::*)()const> struct SFINAE{}; template<typename U> static char Test(SFINAE<U, Object*, &U::operator-> >*); // only change is we hardcoded Object as return type. template<typename U> static uint Test(...); static const bool value = sizeof(Test<T>(0)) == sizeof(char); }; </code>
Wyniki:
<code>void main() { HasOperatorMemberAccessor<PointerX<Object>>::Test<PointerX<Object>>(0); // fails ::value is false; Test => Test(...) HasOperatorMemberAccessorOBJECT<PointerX<Object>>::Test<PointerX<Object>>(0); // works! ::value is true; Test => Test(SFINAE<>*) } </code>
HasOperatorMemberAccessor nie mógł znaleźć funkcji członka PointX „Operator obiektu -> () const”. Używa więc wersji testowej Test (...).
Jednak HasOperatorMemberAccessorOBJECT był w stanie znaleźć „operator obiektu -> () const”. W ten sposób wykorzystuje testową wersję specjalną Test (SFINAE *).
Obie powinny były w stanie znaleźć metodę „Operator obiektu -> () const”; i dlatego oba powinny używać Testowanej wersji testowej (SFINAE *); a zatem HasOperatorMemberAccessor> :: value powinno być prawdziwe dla obu.
Jedyną różnicą między HasOperatorMemberAccessor a HasOperatorMemberAccessorOBJECT jest to, że HasOperatorMemberAccessorOBJECT ma na stałe zakodowaną nazwę obiektu R,
Problem polega na tym, że „decltype (GetReturnType (& U :: operator->))” nie zwraca poprawnie obiektu. Próbowałem wielu różnych pozwoleń na odkrycie typu powrotu. Postępują w następujący sposób:
<code> decltype( GetReturnType(&U::operator->) ) typename decltype( GetReturnType(&U::operator->)) decltype( ((U*)nullptr)->operator->() ) typename decltype( ((U*)nullptr)->operator->() ) </code>
Nic nie działa, dlaczego? Używam MSVC ++ 10.0.