函数模板的部分排序是如何工作的?

3

[temp.func.order]部分中,描述了一种复杂的过程,用于确定一个函数模板是否比另一个更专业。我很难想象和理解这个过程是如何实际工作的。

你能解释一下标准中哪些部分适用于这个简单的例子吗?

template <typename T, int N>
struct array { T data[N]; };

template <typename T>
void foo(T);           // #1

template <typename T, int N>
void foo(array<T, N>); // #2

template <typename T>
void foo(array<T, 1>); // #3


// call: foo(array<int, 1>{})

很明显,#3#2更专业化,而#2#1更专业化,但在标准中如何确定这一点呢?

在标准的C++中,你试图实例化一个包含大小为0的数组成员的类会使你的程序不符合规范。 - Brian Bi
在标准的C++中,你试图实例化一个包含大小为0的数组成员的类会使你的程序不符合规范。 - undefined
@BrianBi 这是一个疏忽,但对于这个问题来说也不重要。我已经将其更改为1 - Jan Schultke
@BrianBi 这是个疏忽,但对于这个问题来说也不重要。我已经将它更改为 1 - undefined
2个回答

3
部分排序背后的基本思想并不复杂。首先,让我们给一些 T 重新命名:
template <typename T>
void foo(T);           // #1

template <typename U, int N>
void foo(array<U, N>); // #2

template <typename V>
void foo(array<V, 1>); // #3

这个想法是每个 array<U, N> 都是一个 T,但并非每个 T 都是一个 array<U, N>。这使得 #2 比 #1 更为专门化。

而且每个 array<V, 1> 都是一个 array<U, N>,但并非每个 array<U, N> 都是一个 array<V, 1>(因为 N 可能不是 1)。这使得 #3 比 #2 更为专门化。

为了检查每个 array<U, N> 是否是一个 T,我们用一个“唯一类型”替换 U,并用一个“唯一值”替换 N。称这些为 UniqT1uniqv1。然后,我们得到类型 array<UniqT1, uniqv1> 并尝试从中推导出 T。很容易:它只是 T = array<UniqT1, uniqv1>。然后我们也尝试反过来:每个 T 都是一个 array<U, N> 吗?为了确定这一点,我们用 UniqT2 替换 T 并尝试在 array<U, N> 中推导出 UN。由于类型 UniqT2 是“唯一”的,无论 UN 是什么,都无法使 array<U, N> 成为与 UniqT2 相同的类型。

同样地,当你在#3中用一个独特的类型替换V时,你可以推导出#2中的UN,但反过来是不行的:用一个独特的类型和值替换#2中的UN,然后你无法推导出#3中的V,因为作为一个独特的值,N并不等于1。这意味着#3比#2更为专门化。

现在关于标准措辞:

"合成一个独特的类型/值"规则是[temp.func.order]/3

然后[temp.func.order]/4告诉你在替换独特的类型/值之后执行推断。

[temp.deduct.partial]/10告诉你如何解释结果:如果推断只在两个方向中的一个成功,那么哪个模板的参数是可以被推断的,那个模板就是较不专业的。

在调用的上下文中,我还应该提到根据[temp.deduct.partial]/3.1,在调用中没有提供实际参数的任何参数类型都将被忽略。

规则的细节当然非常复杂,所以我的总结“每个X都是Y,但反之不成立”远不能解释整个问题。额外的规则涵盖了引用类型的参数、比较非静态成员函数与静态成员函数以及可变参数模板等情况。


1
偏序的基本概念是从模板2的参数类型中尝试推导出模板1的模板参数。如果推导成功,则模板2至少与模板1一样具体。
对于#1,推导从任何类型都会轻松成功,因为它的声明参数类型只是T。类似地,对于#3,推导从#2也会成功,因为我们可以推导出T2=T3和N2=0。其他方向不成功,因此在这种特殊情况下出现了明显的全序关系。

在我看来,最后一句话有些令人困惑,因为它可能让人误以为部分排序可以导致完全排序。在这种情况下是成立的,因此没有歧义,但是在其他设计中,存在一对特化的情况,其中没有一个可以被认为比另一个更专业化,从而可能导致歧义。不是吗? - Oersted
在我看来,最后一句话有些混淆,因为它可能让人误以为偏序关系可以导致全序关系。在这种情况下是成立的,因此没有歧义,但是在其他设计中,可能存在一对特化的情况,其中没有一个可以被认为比另一个更专业,从而导致可能的歧义。不是吗? - undefined
@Oersted:当然。我会期望“偏序”这个术语已经很明显了,但我添加了一个小的澄清。 - Davis Herring
@Oersted:当然。我本来以为“偏序”这个术语已经很明显了,但我加了一个小的澄清。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接