如果两者都可行,编译器如何确定使用 SFINAE 的函数和标准函数?
How does the compiler determine between a function using SFINAE and a standard function if both are viable?
考虑以下代码:
#include <iostream>
#include <type_traits>
template <typename T>
class A
{
public:
// Allow func to be called if T is the const version of T2
// e.g., T is 'int const' and T2 is 'int'
template <typename T2,
typename = typename std::enable_if<
std::is_same<T, T2 const>::value>::type>
void func(A<T2> const &)
{
std::cout << "Conversion" << std::endl;
}
// Allow func to be called for same version of T
void func(A const &)
{
std::cout << "No conversion" << std::endl;
}
};
int main()
{
A<int const> a;
a.func(A<int const>{});
return 0;
}
此代码在使用 GCC-8.3 编译时会编译并生成输出 No conversion
- 它 select 编辑了不使用 std::enable_if
的 func
版本。但是,如果我注释掉 func
的第二个版本,它仍然会编译并现在生成输出 Conversion
。换句话说,A
中的两个版本的 func
都可用于此方法。鉴于两个重载都是可行的,编译器使用什么特定规则 select func(A const &)
而不是另一个版本 (func(A<T2> const &)
)?
规则是,如果非函数模板和函数模板特化具有相同的签名,则选择非函数模板而不是模板特化。这可以在 [over.match.best]/2
中找到
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
[...]
- F1 is not a function template specialization and F2 is a function template specialization [...]
您可以阅读有关重载解析的内容 here。特别是
If any candidate is a function template, its specializations are generated using template argument deduction, and such specializations are treated just like non-template functions except where specified otherwise in the tie-breaker rules.
然后
Best viable function
For each pair of viable function F1 and F2, the implicit conversion sequences from the i-th argument to i-th parameter are ranked to determine which one is better [...]
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
[...]
4) [...] F1 is a non-template function while F2 is a template specialization
基本上相同的规则适用于这个更简单的示例:
#include<iostream>
template <typename T>
void foo(T i) { std::cout << "template" ; }
void foo(int i) { std::cout << "non template"; }
int main() {
foo(1); // non template
}
考虑以下代码:
#include <iostream>
#include <type_traits>
template <typename T>
class A
{
public:
// Allow func to be called if T is the const version of T2
// e.g., T is 'int const' and T2 is 'int'
template <typename T2,
typename = typename std::enable_if<
std::is_same<T, T2 const>::value>::type>
void func(A<T2> const &)
{
std::cout << "Conversion" << std::endl;
}
// Allow func to be called for same version of T
void func(A const &)
{
std::cout << "No conversion" << std::endl;
}
};
int main()
{
A<int const> a;
a.func(A<int const>{});
return 0;
}
此代码在使用 GCC-8.3 编译时会编译并生成输出 No conversion
- 它 select 编辑了不使用 std::enable_if
的 func
版本。但是,如果我注释掉 func
的第二个版本,它仍然会编译并现在生成输出 Conversion
。换句话说,A
中的两个版本的 func
都可用于此方法。鉴于两个重载都是可行的,编译器使用什么特定规则 select func(A const &)
而不是另一个版本 (func(A<T2> const &)
)?
规则是,如果非函数模板和函数模板特化具有相同的签名,则选择非函数模板而不是模板特化。这可以在 [over.match.best]/2
中找到Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
[...]
- F1 is not a function template specialization and F2 is a function template specialization [...]
您可以阅读有关重载解析的内容 here。特别是
If any candidate is a function template, its specializations are generated using template argument deduction, and such specializations are treated just like non-template functions except where specified otherwise in the tie-breaker rules.
然后
Best viable function
For each pair of viable function F1 and F2, the implicit conversion sequences from the i-th argument to i-th parameter are ranked to determine which one is better [...]
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and [...]
4) [...] F1 is a non-template function while F2 is a template specialization
基本上相同的规则适用于这个更简单的示例:
#include<iostream>
template <typename T>
void foo(T i) { std::cout << "template" ; }
void foo(int i) { std::cout << "non template"; }
int main() {
foo(1); // non template
}