问题
While trying to answer this question I wanted to suggest the use of enable_if + disable_if to allow the overload of a method based on the fact that a type was (or not) polymorphic.
So I created a small test file:
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;
}
which seems quite tame.
However gcc (3.4 ...) choke on this:
test.cpp: In function
int main(int, char**):
test.cpp:29: error: call of overloadedaddress_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]
It seems rather clear to my human mind which overload should be used here. I mean it seems clear that I have defined an alternative and only one function can be used at a time... and I would have thought that SFINAE would take care of invalidating the unnecessary overload.
I patched it up by using ... (ellipsis) instead of disable_if and requiring a dummy second argument... but I am still interested in why the compiler choke on this.
回答1:
The compiler choked because you forgot the trailing ::type on enable_if and disable_if. The templates are always defined; it is just that the member type is present if and only if the expression is true (for enable_if) or false (for 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); }
Without the trailing ::type, your function templates just create overloads that take pointers to instances of enable_if or disable_if as the second parameter. With the trailing ::type, the templates either create an overload with a second parameter of type void*, or the overload is removed (i.e. the desired behaviour).
回答2:
Using the "return type" version of enable_if works 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;
}
来源:https://stackoverflow.com/questions/3491848/enable-if-disable-if-combination-provokes-an-ambiguous-call