为什么SFINAE仅适用于这两个看似相同的功能之一?

问题描述 投票:0回答:1

以下代码无法编译(使用clang 7.0, - std = c ++ 17):

struct Foo {
    void foo() {}
};
struct Bar {
    void bar() {}
};
struct Both {
    void foo() {}
    void bar() {}
};

template <typename T, typename>
void DoStuff(T input) {
    input.foo();
}

template <typename T, typename...>
void DoStuff(T input) {
    input.bar();
}

int main(int argc, char** argv) {
    DoStuff(Foo());
    return 0;
}

错误是:

<source>:19:11: error: no member named 'bar' in 'Foo'
    input.bar();
    ~~~~~ ^

<source>:23:5: note: in instantiation of function template specialization 'DoStuff<Foo>' requested here
    DoStuff(Foo());

但是,如果你将Foo()更改为Bar()(或Both()),它编译就好了。在Bar()案例中,这表明SFINAE正在生效;在Both()案例中,它表明typename...重载具有较低的优先级,因此当两者都适用时选择另一个。

但我不明白为什么SFINAE适用于Bar()案件但不适用于Foo()案件?

c++ templates sfinae
1个回答
2
投票

这里没有SFINAE。所有对DoStuff的电话都会打电话

template <typename T, typename...>
void DoStuff(T input) {
    input.bar();
}

原因是这样的

template <typename T, typename>
void DoStuff(T input) {
    input.foo();
}

需要两个模板参数

template <typename T, typename...>
void DoStuff(T input) {
    input.bar();
}

适用于1个或多个模板参数(变量包允许为空)。所以当你打电话

DoStuff(Foo());
// or
DoStuff(Bar());
//or
DoStuff(Both());

你只能推导出一个模板参数,唯一可行的候选者就是

template <typename T, typename...>
void DoStuff(T input) {
    input.bar();
}

如果你曾经使用过

DoStuff<Foo, any_other_type>(Foo());

然后你会得到歧义错误,因为它匹配两个模板。

© www.soinside.com 2019 - 2024. All rights reserved.