为什么SFINAE无法跨多个继承工作?

时间:2019-12-04 14:19:20

标签: c++ templates sfinae

代码如下:

#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();
}


在调用d.foo()时,尽管fooClassWithDisabledFoo::foo禁用,但是clang和gcc都说对enable_if的调用是模棱两可的。如果将foo的定义从ClassWithFoo移到Derived,代码将编译。

为什么不起作用,如何使它起作用?

1 个答案:

答案 0 :(得分:8)

您的示例中没有发生重载解决方案,因此SFINAE无关紧要。

此处的关键是名称查询在重载解析之前发生。名称查找将找到一个重载集,然后对找到的重载集执行重载解析。

名称必须映射到单个对象类型内的单个集合。在您的情况下,相同的名称映射到两个不同子对象的成员,因此名称查找是不明确的。一个直接的解决方案是使用声明添加:

class Derived: public ClassWithFoo, public ClassWithDisabledFoo<double>
{
    using ClassWithFoo::foo;
    using ClassWithDisabledFoo::foo;
};

这将名称引入Derived中,现在可以明确地找到该声明以引用由我们引入的成员组成的重载集。