为什么 SFINAE 只适用于这两个看似相同的函数之一?
Why does SFINAE only apply to one of these two seemingly identical functions?
以下代码无法编译(使用 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()
的情况?
这里没有 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());
然后你会得到一个歧义错误,因为它匹配两个模板。
以下代码无法编译(使用 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()
的情况?
这里没有 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());
然后你会得到一个歧义错误,因为它匹配两个模板。