SFINAE - Tentando determinar se o tipo de modelo tem função de membro com tipo de retorno 'variável'
Tem problemas com o SFINAE. Eu preciso ser capaz de determinar se um tipo tem uma função de membro operator-> definida, independentemente do seu tipo de retorno. Exemplo a seguir.
Esta classe no testador. Define operator -> () com um tipo de retorno de X *. Assim, não sei o que é 'X' para codificá-lo em todos os lugares.
template <class X>
class PointerX
{
...
X* operator->() const;
...
}
Esta classe tenta determinar se o passado em T possui um método operator-> defined; independentemente do que o operador-> tipo de retorno é.
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);
};
Esta classe é exatamente a mesma que acima, exceto que operator-> return type deve ser 'Object'.
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);
};
Resultados:
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 não conseguiu encontrar a função de membro do PointX "Object operator -> () const". Por isso, usa a versão genérica Test Test (...).
No entanto, HasOperatorMemberAccessorOBJECT foi capaz de encontrar o "Object operator -> () const" do PointX. Assim, utiliza Teste de versão especializada Teste (SFINAE *).
Ambos deveriam ter conseguido encontrar o método "Operador de objetos -> () const"; e, portanto, ambos devem usar o teste de versão especializada do Test (SFINAE *); e, portanto, HasOperatorMemberAccessor> :: value deve ser verdadeiro para ambos.
A única diferença entre HasOperatorMemberAccessor e HasOperatorMemberAccessorOBJECT é que HasOperatorMemberAccessorOBJECT possui o typename R codificado para objeto,
Portanto, o problema é que "decltype (GetReturnType (& U :: operator->))" não está retornando o objeto corretamente. Eu tentei várias permissões diferentes para descobrir o tipo de retorno. Eles seguem o seguinte:
decltype( GetReturnType(&U::operator->) )
typename decltype( GetReturnType(&U::operator->))
decltype( ((U*)nullptr)->operator->() )
typename decltype( ((U*)nullptr)->operator->() )
Nenhum trabalho, por quê? Estou usando o MSVC ++ 10.0.