编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行



考虑以下代码:

#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-它选择了不使用std::enable_iffunc版本。但是,如果我注释掉func的第二个版本,它仍然会编译并生成输出Conversion。换句话说,A中的两个版本的func都可用于此方法。假设两个重载都是可行的,编译器使用什么特定规则来选择func(A const &)而不是另一个版本(func(A<T2> const &)(?

规则是,如果非函数模板和函数模板专用化具有相同的签名,则选择非函数模板而不是模板专用化。这可以在[over.match.best]/2 中找到

给定这些定义,如果对于所有自变量i,ICSi(F1(不是比ICSi(F2(更差的转换序列,则可行函数F1被定义为比另一个可行函数F2更好的函数,然后

[…]

  • F1不是函数模板专用化,F2是函数模板专用[…]

您可以在此处阅读有关过载解决方案的信息。特别是

如果任何候选函数是函数模板,则使用模板参数推导生成其专门化,并且除非平局决胜规则中另有规定,否则将像对待非模板函数一样对待此类专门化。

然后

最佳可行函数

对于每对可行函数F1和F2,对从第i个自变量到第i个参数的隐式转换序列进行排序,以确定哪一个更好[…]

如果F1的所有变元的隐式转换不比F2的所有变位的隐式转化差,则F1被确定为比F2更好的函数,并且[…]

4( 〔…〕F1是一个非模板函数,而F2是一个模板专用

基本上相同的规则适用于这个更简单的例子:

#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
}

最新更新