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.
<code>template <class X> class PointerX { ... X* operator->() const; ... } </code>
Esta classe tenta determinar se o passado em T possui um método operator-> defined; independentemente do que o operador-> tipo de retorno é.
<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>
Esta classe é exatamente a mesma que acima, exceto que operator-> return type deve ser '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>
Resultados:
<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 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:
<code> decltype( GetReturnType(&U::operator->) ) typename decltype( GetReturnType(&U::operator->)) decltype( ((U*)nullptr)->operator->() ) typename decltype( ((U*)nullptr)->operator->() ) </code>
Nenhum trabalho, por quê? Estou usando o MSVC ++ 10.0.