Проблемы с SFINAE. Мне нужно иметь возможность определить, имеет ли Type оператор функции-члена ->, определенный независимо от его возвращаемого типа. Пример следует.
Этот класс в тестере. Он определяет оператор -> ()с возвращаемым типом X *. Таким образом, я не буду знать, что такое «X», чтобы жестко закодировать его везде.
template <class X>
class PointerX
{
...
X* operator->() const;
...
}
Этот класс пытается определить, имеет ли переданный в T оператор метода -> определенный; независимо от того, какой оператор -> возвращает тип.
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);
};
Этот класс точно такой же, как и выше, за исключением того, что оператор -> возвращаемый тип должен быть «Объект».
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);
};
Результаты:
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<>*)
}
HasOperatorMemberAccessor не удалось найти функцию-член PointX «Оператор объекта -> ()const». Поэтому он использует общую версию Test Test (... ).
Однако HasOperatorMemberAccessorOBJECT смог найти PointX «Оператор объекта -> ()const». При этом используется специализированная версия Test Test(SFINAE*).
Оба должны были найти метод «Object operator -> ()const»; и поэтому оба должны использовать специализированную версию Test Test (SFINAE *); и, таким образом, значение HasOperatorMemberAccessor> ::должно быть истинным для обоих.
Единственная разница между HasOperatorMemberAccessor и HasOperatorMemberAccessorOBJECT заключается в том, что HasOperatorMemberAccessorOBJECT имеет имя типа R, жестко запрограммированное для объекта,
Таким образом, проблема заключается в том, что «decltype (GetReturnType (&U ::оператор -> ))" не возвращает Object правильно. Я пробовал несколько различных разрешений на обнаружение возвращаемого типа. Они идут следующим образом:
decltype( GetReturnType(&U::operator->) )
typename decltype( GetReturnType(&U::operator->))
decltype( ((U*)nullptr)->operator->() )
typename decltype( ((U*)nullptr)->operator->() )
Ничего не работает, почему? Я использую MSVC++ 10.0.