我已经注意到很多关于模板的问题,这些问题是由于部分排序规则造成的,而且它们似乎彼此不一致。我以为我会自己深入研究这个标准并把它搞得一团糟。忍受我。
gcc和clang似乎都同意用于确定模板排序的算法,但该算法实际上并未出现在标准中。没有特别的顺序:
template <typename T> void foo(T, T); // (1)
template <typename T, typename U> void foo(T, U); // (2)
temp.deduct.type / 2清楚地表明,Ps必须有一组推导出的值。但是在偏序规则中没有这样的陈述。所描述的算法仅进行成对P / A匹配,因此从(2)到(1)通过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)
此处,如果为(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; };
在合成和一致性期间没有模板实例化,(2)==&gt; (1)扣除失败。但是如果我们考虑(1)==&gt; (2)致电,我们将T
与Unique1
匹配,然后将未推断的上下文typename identity<Unique1>::type
与Unique1
匹配,但这将是替代失败。似乎gcc和clang采用的方法(两者都更喜欢这里的)是忽略非推导的上下文参数,只要该参数类型是从匹配的不同模板参数类型推导出来的。 / p>
gcc / clang采取的方法是有道理的,但我不认为它在标准中过于清晰。有人可以验证我的逻辑吗?