enable_if + disable_if combinazione provoca una chiamata ambigua
Domanda
Durante il tentativo di risposta questa domanda volevo suggerire l'uso di enable_if
+ disable_if
per consentire il sovraccarico di un metodo basato sul fatto che un tipo è (o non) polimorfico.
Così ho creato un piccolo file di test:
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;
}
che sembra piuttosto noiosi.
Tuttavia gcc (3,4 ...) soffocare su questo:
test.cpp: In funzione
int main(int, char**)
:
test.cpp: 29: errore: Chiamata diaddress_of(N*)
sovraccarico è
ambiguo test.cpp: 17: Nota: i candidati sono: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]
E sembra piuttosto chiaro alla mia mente umana che di sovraccarico deve essere utilizzato qui. Insomma sembra chiaro che ho definito un'alternativa e una sola funzione può essere utilizzata in un momento ... e avrei pensato che SFINAE sarebbe preso cura di invalidare il sovraccarico inutile.
I rattoppato in su utilizzando ...
(puntini di sospensione) al posto di disable_if
e che richiedono un secondo argomento fittizio ... ma sono ancora interessati a Perché lo starter compilatore su questo.
Soluzione
Il compilatore soffocato perché si è dimenticato il ::type
finale sul enable_if
e disable_if
. I modelli sono sempre definiti; è solo che il type
membro è presente se e solo se l'espressione è true
(per enable_if
) o false
(per 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); }
Senza la ::type
finale, i modelli di funzione basta creare sovraccarichi che prendono puntatori a istanze di enable_if
o disable_if
come secondo parametro. Con il ::type
posteriore, i modelli sia creano un sovraccarico con un secondo parametro di tipo void*
, o sovraccarico viene rimossa (cioè il comportamento desiderato).
Altri suggerimenti
Utilizzando la versione "tipo di ritorno" di enable_if lavora in 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;
}