为什么 SFINAE 不能跨多重继承工作?

use*_*683 5 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();
}


Run Code Online (Sandbox Code Playgroud)

在调用时d.foo(),clang 和 gcc 都表示调用foo是不明确的,尽管ClassWithDisabledFoo::fooenable_if. 如果我将foo定义从移动ClassWithFooDerived,代码就会编译。

为什么这不起作用,我怎样才能使它起作用?

Sto*_*ica 9

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

这里的关键是名称查找发生重载解析之前。名称查找找到一个重载集,然后对找到的集执行重载解析。

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

class Derived: public ClassWithFoo, public ClassWithDisabledFoo<double>
{
    using ClassWithFoo::foo;
    using ClassWithDisabledFoo::foo;
};
Run Code Online (Sandbox Code Playgroud)

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