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

huangapple go评论70阅读模式
英文:

How does partial ordering of function templates work?

问题

以下是翻译好的部分:

“[[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


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

直观上,“#3”比“#2”更为专业化,而“#2”比“#1”更为专业化,但标准中如何真正确定这一点?

英文:

The section [temp.func.order] describes a complicated process by which it is determined whether one function template is more specialized than another. I am having trouble visualizing, and understanding how this process actually works.

Could you explain which sections in the standard apply in this simple example?

template &lt;typename T, int N&gt;
struct array { T data[N]; };

template &lt;typename T&gt;
void foo(T);           // #1

template &lt;typename T, int N&gt;
void foo(array&lt;T, N&gt;); // #2

template &lt;typename T&gt;
void foo(array&lt;T, 1&gt;); // #3


// call: foo(array&lt;int, 1&gt;{})

It's intuitively obvious #3 is more specialized than #2, which is more specialized than #1, but how is this really determined in the standard?

答案1

得分: 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>?为了确定这一点,我们将 T 替换为 UniqT2 并尝试推断 UNarray<U, N> 中。由于类型 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,但反之则不是" 的摘要远不能解释整个情况。附加规则涵盖了诸如引用类型的参数、比较非静态成员函数与静态成员函数以及可变模板等情况。

英文:

The basic idea behind partial ordering is not very complicated. First, let's rename some of the T's:

template &lt;typename T&gt;
void foo(T);           // #1

template &lt;typename U, int N&gt;
void foo(array&lt;U, N&gt;); // #2

template &lt;typename V&gt;
void foo(array&lt;V, 1&gt;); // #3

The idea is that every array&lt;U, N&gt; is a T, but not every T is an array&lt;U, N&gt;. That makes #2 more specialized than #1.

And every array&lt;V, 1&gt; is an array&lt;U, N&gt;, but not every array&lt;U, N&gt; is an array&lt;V, 1&gt; (since N might not be 1). That makes #3 more specialized than #2.

In order to check whether every array&lt;U, N&gt; is a T, we replace U with a "unique type" and N with a "unique value". Call these UniqT1 and uniqv1. Then, we get the type array&lt;UniqT1, uniqv1&gt; and we attempt to deduce T from this. That's easy: it's just T = array&lt;UniqT1, uniqv1&gt;. Then we also try the same thing the other way around: is every T an array&lt;U, N&gt;? To determine this, we replace T with UniqT2 and attempt to deduce U and N in array&lt;U, N&gt;. Since the type UniqT2 is "unique", there is no way to make array&lt;U, N&gt; the same type as UniqT2 no matter what U and N are.

Similarly when you replace V in #3 with a unique type, you can deduce U and N in #2, but you can't do it the other way around: replace U and N with a unique type and unique value in #2, and then you can't deduce V in #3, because N, being a unique value, isn't equal to 1. That implies that #3 is more specialized than #2.

Now as for the standard wording:

The "synthesize a unique type/value" rule is [temp.func.order]/3.

Then [temp.func.order]/4 tells you to perform deduction after substituting the unique types/values.

[temp.deduct.partial]/10 tells you how to interpret the result: if deduction only succeeds in one of the two directions, then whichever template's arguments are the ones that could be deduced, that one is the less specialized one.

In the context of a call, I should additionally mention that according to [temp.deduct.partial]/3.1 any parameter types for which no actual argument was provided in the call are ignored.

The details of the rules are of course enormously complicated, so my summary of "every X is a Y but not vice versa" does not come close to explaining the whole thing. The additional rules cover situations like parameters of reference type, comparing non-static member functions with static member functions, and variadic templates.

答案2

得分: 1

基本思想部分排序是尝试从模板2的参数类型中推导模板1的模板参数。如果推导成功,模板2至少与模板1一样专业。

从任何东西中推导都可以轻松成功,因为它的声明参数类型只是 T。 类似地,从#3中推导出#2也会成功,因为我们可以推导 T2 = T3N2 = 0。 其他方向不成功,因此在这种特殊情况下明显的顺序出现。

英文:

The basic idea of partial ordering is that one tries deducing the template arguments for template 1 from the parameter types of template 2. If deduction succeeds, template 2 is at least as specialized as template 1.

Deduction trivially succeeds for #1 from anything since its declared parameter type is just T. #2 similarly succeeds from #3 since we can deduce T<sub>2</sub>=T<sub>3</sub> and N<sub>2</sub>=0. The other directions do not succeed, so the obvious total order emerges in this particular case.

huangapple
  • 本文由 发表于 2023年6月13日 07:35:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76460871.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定