Reputation: 1483
Here's the code:
#include <utility>
#include <type_traits>
template <class T>
class ClassWithDisabledFoo
{
public:
template <class U = T, std::enable_if_t<std::is_integral<U>::value, int> = 0>
void foo(){}
};
class ClassWithFoo
{
public:
void foo(){}
};
class Derived: public ClassWithFoo, public ClassWithDisabledFoo<double>
{
};
void test()
{
Derived d;
d.foo();
}
At the point of calling d.foo()
, both clang and gcc say that the call to foo
is ambiguous, despite ClassWithDisabledFoo::foo
being disabled by enable_if
. If I move the foo
definition from ClassWithFoo
to Derived
, the code compiles.
Why doesn't this work and how can I make it work?
Upvotes: 5
Views: 99
Reputation: 170064
There is no overload resolution happening in your example, so the SFINAE doesn't matter.
The key here is that name lookup happens before overload resolution. Name lookup finds an overload set, and then overload resolution is performed on the set that was found.
The name has to map to a single set inside a single object type. In your case, the same name maps to members of two different sub-objects, so the name lookup is ambiguous. An immediate solution is to add using declarations:
class Derived: public ClassWithFoo, public ClassWithDisabledFoo<double>
{
using ClassWithFoo::foo;
using ClassWithDisabledFoo::foo;
};
This introduces the name into Derived
, where the declaration can now be unambiguously found to refer to an overload set composed of the members we brought in.
Upvotes: 9