SFINAE没有避免歧义调用



编译代码:

#include <iostream>

template <int N>
struct TestClass {
    template <int N2, typename std::enable_if<N2 == N, int>::type = 0>
    void doAction() { std::cout << "TestClass::doAction<" << N << ">();n"; }
};
struct HostClass : public TestClass<1>, public TestClass<2> {
};

int main(int argc, const char * argv[]) {
    HostClass hostClass;
    hostClass.doAction<1>();
    hostClass.doAction<2>();
    return 0;
}

会导致歧义调用错误,因为doAction同时在TestClass<1>TestClass<2>父类中。

main.cpp:33:15:在不同类型的多个基类中发现成员'doAction'

std::enable_if不会使这种模糊性失效?

编辑:

我认为这种模棱两可的真正原因和这个问题是一样的:

为什么具有相同名称但不同签名的多继承函数不被视为重载函数?

歧义可以用using关键字解决,如答案所示:

#include <iostream>

template <int N>
struct TestClass {
    template <int N2, typename std::enable_if<N2 == N, int>::type = 0>
    void doAction() { std::cout << "TestClass::doAction<" << N << ">();n"; }
};
struct HostClass : public TestClass<1>, public TestClass<2> {
    using TestClass<1>::doAction;
    using TestClass<2>::doAction;
};
int main(int argc, const char * argv[]) {
    HostClass hostClass;
    hostClass.doAction<1>();    // OK, compile
    hostClass.doAction<2>();    // OK, compile
    //hostClass.doAction<3>();  // OK, doesn't compile : "candidate template ignored: disabled by 'enable_if' [with N2 = 3]"
    return 0;
}

我不知道这是不是@skypjack answer的意思,但我还是让它替代了它的方法。

它会(让我说)放在替换后的两个函数之一。
无论如何,首先,编译器必须决定你打算使用哪个函数,当你调用它作为doAction<1>然后它可以继续进行替换,最终扔掉选择的函数,因为sfinae。在调用时,它们都是有效的候选者,并且调用实际上是二义性的。

请注意,正如@Peregring-lk在评论中建议的那样,TestClass<1>::doActionTestClass<2>::doAction是放置在不同命名空间中的两个不同的函数,它们不是同一函数的重载。
这实际上是误解的一个常见来源。


你可以很容易地解决这个问题,如下所示:

#include <iostream>
template <int N>
struct TestClass {
    void doAction() { std::cout << "TestClass::doAction<" << N << ">();n"; }
};
struct HostClass : public TestClass<1>, public TestClass<2> {
    template<int N>
    void doAction() { return TestClass<N>::doAction(); }
};

int main(int argc, const char * argv[]) {
    HostClass hostClass;
    hostClass.doAction<1>();
    hostClass.doAction<2>();
    return 0;
}