Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't SFINAE work across multiple inheritance?

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?

like image 348
user697683 Avatar asked Dec 04 '19 14:12

user697683


1 Answers

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.

like image 189
StoryTeller - Unslander Monica Avatar answered Nov 16 '22 02:11

StoryTeller - Unslander Monica