函数模板重载解析,依赖和非依赖参数

Mes*_*kon 8 c++ templates language-lawyer c++17

鉴于以下程序

#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;
}
Run Code Online (Sandbox Code Playgroud)

GCC 和 Clang 都打印1了这个程序。这个程序是否保证1按标准打印?

我试图在这里找到答案但无法破译。看起来函数模板可能是等效的,因此会破坏 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; }
Run Code Online (Sandbox Code Playgroud)

做出改变?

T.C*_*.C. 6

这是沼泽标准的部分排序。我们将唯一类型替换到其中一个函数模板中,并尝试根据它推断出另一个。两种方法都可以,如果推论只在一个方向成功,我们就有了一个命令。如果您想阅读晦涩难懂的规则,请参阅 [temp.func.order] 和 [temp.deduct.partial]。

所以在这里,

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

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

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


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