模板部分排序规则是否未指定?

use*_*709 5 c++ templates language-lawyer

我已经注意到很多关于模板的问题,这些问题是由于部分排序规则造成的,而且它们似乎彼此不一致.我以为我会自己深入了解标准并将其排除在外.忍受我.

gcc和clang似乎都同意用于确定模板排序的算法,但该算法实际上并未出现在标准中.没有特别的顺序:

推导值的一致性:

template <typename T> void foo(T, T); // (1)
template <typename T, typename U> void foo(T, U); // (2)
Run Code Online (Sandbox Code Playgroud)

temp.deduct.type/2清楚地表明Ps必须有一组推导出的值.但是在偏序规则中没有这样的陈述.所描述的算法仅进行成对P/A匹配,因此从(2)到(1)via的合成调用foo(U{}, V{})可以成功推导.gcc和clang都认为(1)更专业.

类型合成模板实例化

template <typename T>
struct identity { using type = T; };

template<typename T> void bar(T, T ); // (1) 
template<typename T> void bar(T, typename identity<T>::type ); // (2)
Run Code Online (Sandbox Code Playgroud)

这里,如果为(2)Unique2和()合成typename identity<Unique2>::type == Unique2,那么类型推导将在两个方向上成功并且调用bar(0,0)将是模糊的.然而,似乎是两种编译器,而不是简单地把typename identity<Unique2>::type作为Unique2_b,从而由式(2)(1)失败(基于隐含缺少一致性规则)制作模板扣除.

非推导的上下文遗漏

与前面的示例相同,但现在定义:

template <typename T> struct identity; template <> struct identity<int> { using type = int; };
Run Code Online (Sandbox Code Playgroud)

在合成和一致性期间没有模板实例化时,(2)==>(1)推导失败.但是,如果我们考虑到(1)==>(2)调用,我们会匹配T对Unique1,然后让非推断上下文typename identity<Unique1>::type来匹配Unique1,但是这将是一个替代的失败.似乎gcc和clang采用的方法(两者都更喜欢这里的)是忽略非推导的上下文参数,只要该参数类型是从匹配的不同模板参数类型推导出来的.

我在这里有意义吗?

gcc/clang采取的方法是有道理的,但我不认为它在标准中太清楚了.有人可以验证我的逻辑吗?