2010-08-16 6 views
5

Al tratar de responder this question quería sugerir el uso de enable_if + disable_if para permitir la sobrecarga de un método basado en el hecho de que era un tipo (o no) polimórfica.enable_if + disable_if combinación provoca una llamada ambigua

Así que he creado un pequeño archivo de prueba:

template <class T> 
void* address_of(T* p, 
       boost::enable_if< boost::is_polymorphic<T> >* dummy = 0) 
{ return dynamic_cast<void*>(p); } 

template <class T> 
void* address_of(T* p, 
       boost::disable_if< boost::is_polymorphic<T> >* dummy = 0) 
{ return static_cast<void*>(p); } 

struct N { int x; }; 


int main(int argc, char* argv[]) 
{ 
    N n; 
    std::cout << address_of(&n) << std::endl; 
    return 0; 
} 

que parece bastante dócil.

Sin embargo gcc (3,4 ...) en este estrangulador:

test.cpp: In function int main(int, char**) :
test.cpp:29: error: call of overloaded address_of(N*) is ambiguous
test.cpp:17: note: candidates are: void* address_of(T*, boost::enable_if<boost::is_polymorphic<T>, void>*) [with T = N]
test.cpp:20: note: void* address_of(T*, boost::disable_if<boost::is_polymorphic<T>, void>*) [with T = N]

Parece bastante claro a la mente humana, que sobrecargue se debe utilizar aquí. Quiero decir que parece claro que he definido una alternativa y que solo se puede usar una función a la vez ... y hubiera pensado que SFINAE se encargaría de invalidar la sobrecarga innecesaria.

Lo paré usando ... (puntos suspensivos) en lugar de disable_if y requiriendo un segundo argumento ficticio ... pero todavía estoy interesado en por qué el compilador se atraganta con esto.

Respuesta

11

El compilador ahogada porque se le olvidó la ::type por detrás en enable_if y disable_if. Las plantillas siempre están definidas; es solo que el miembro type está presente si y solo si la expresión es true (para enable_if) o false (para disable_if).

template <class T> 
void* address_of(T* p, 
       typename boost::enable_if< boost::is_polymorphic<T> >::type* dummy = 0) 
{ return dynamic_cast<void*>(p); } 

template <class T> 
void* address_of(T* p, 
       typename boost::disable_if< boost::is_polymorphic<T> >::type* dummy = 0) 
{ return static_cast<void*>(p); } 

Sin la ::type de salida, las plantillas de función simplemente crear sobrecargas que toman punteros a instancias de enable_if o disable_if como el segundo parámetro. Con el ::type posterior, las plantillas crean una sobrecarga con un segundo parámetro de tipo void*, o se elimina la sobrecarga (es decir, el comportamiento deseado).

+0

¡Maldito! Sabía que debería funcionar ... –

0

Usando el "tipo de retorno" versión de enable_if trabaja en 3.4.4: gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)

#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits/is_polymorphic.hpp> 
#include <iostream> 

template <class T> 
typename boost::enable_if< boost::is_polymorphic<T>, void* >::type 
address_of(T* p) 
{ return dynamic_cast<void*>(p); } 

template <class T> 
typename boost::disable_if< boost::is_polymorphic<T>, void* >::type 
address_of(T* p) 
{ return static_cast<void*>(p); } 

struct N { int x; }; 


int main(int argc, char* argv[]) 
{ 
    N n; 
    std::cout << address_of(&n) << std::endl; 
    return 0; 
} 
Cuestiones relacionadas