函数模板重载决议,依赖和非依赖参数

Function template overload resolution, dependent and non-dependent parameters

给定以下程序

#include <iostream>

template<class T> struct id { using type = T; };

template<class T1, class T2>
int func(T1, T2) { return 0; }

template<class T1, class T2>
int func(typename id<T1>::type, typename id<T2>::type) { return 1; }

int main()
{
    std::cout << func<int, int>(0, 0) << std::endl;
}

GCC 和 Clang 都为该程序打印 1。这个程序保证按标准打印1吗?

我试图找到答案 here 但无法破译。看起来函数模板可能是等效的,因此会破坏 ODR,但我不确定。

是否将第二个功能模板更改为

template<class T>
using id_type = typename id<T>::type;

template<class T1, class T2>
int func(id_type<T1>, id_type<T2>) { return 1; }

有所作为?

以下func重载

// Denote as overload F.
template<class T1, class T2>
int func(typename id<T1>::type, typename id<T2>::type) { return 1; }

比以下func重载

更专业
// Denote as overload G.
template<class T1, class T2>
int func(T1, T2) { return 0; }

因此,重载决策选择了前者。


(以下所有 ISO 标准参考均参考 N4659: March 2017 post-Kona working draft/C++17 DIS

funcGF 重载的部分排序受以下因素支配:

这是沼泽标准偏序。我们将唯一类型替换为一个函数模板,并尝试根据它推导另一个。双向进行,如果演绎只在一个方向上成功,我们就有一个命令。如果您想阅读奥术规则,请参阅 [temp.func.order] 和 [temp.deduct.partial]。

所以在这里,

  • T1=U1, T2=U2 代入第一个重载的函数类型会产生 int f(U1, U2); 我们可以从中推导出第二个重载中的 T1T2 吗?不;两者都在非推导的上下文中。因此,演绎失败。
  • T1=U1, T2=U2 代入第二个重载会产生 int f(id<U1>::type, id<U2>::type)(这是在定义上下文中进行的,因此我们不能进一步代入 id - 某处可能有专门化) .我们可以从中推导出第一个重载中的 T1T2 吗?是的,通过推导 T1 = id<U1>::typeT2 = id<U2>::type。扣分成功

由于推导仅在一个方向上成功 - 从转换后的第二个方向推导第一个 - 第二个比第一个更专业,并且优先由重载决议选择。

别名模板大小写没有任何变化。


这些模板既不等价也不在功能上等价。