enable_if + disable_if combinación provoca una llamada ambigua
Pregunta
Al tratar de responder a esta pregunta quería sugerir el uso de enable_if
+ disable_if
para permitir la sobrecarga de un método basado en el hecho de que un tipo era (o no) polimórfico.
Así que creó 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 a dominar.
Sin embargo gcc (3,4 ...) ahogarse con esto:
test.cpp: En
int main(int, char**)
función:
test.cpp: 29: error: Llamada deaddress_of(N*)
sobrecargado es ambigua
test.cpp: 17: nota: los candidatos son:void* address_of(T*, boost::enable_if<boost::is_polymorphic<T>, void>*)
[con T = N]
test.cpp: 20: nota:void* address_of(T*, boost::disable_if<boost::is_polymorphic<T>, void>*)
[con T = N]
Parece bastante claro a la mente humana que la sobrecarga se debe utilizar aquí. Es decir, parece claro que he definido una alternativa y sólo una función se puede utilizar a la vez ... y yo habría pensado que SFINAE se haría cargo de invalidar la sobrecarga innecesaria.
Me parcheado la conexión utilizando ...
(puntos suspensivos) en lugar de disable_if
y requiriendo un segundo argumento ficticio ... pero sigo interesado en saber por qué el estrangulador compilador en esto.
Solución
El compilador ahogada porque se le olvidó la ::type
se arrastra en enable_if
y disable_if
. Las plantillas siempre se definen; es sólo que la type
miembro está presente si y sólo si la expresión es true
(por enable_if
) o false
(por 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 basta con crear sobrecargas que toman punteros a instancias de enable_if
o disable_if
como el segundo parámetro. Con la ::type
de salida, las plantillas o bien crean una sobrecarga con un segundo parámetro de tipo void*
, o se elimine la sobrecarga (es decir, el comportamiento deseado).
Otros consejos
El uso de la versión "tipo de retorno" 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;
}