什么是模板推导中的部分排序程序

yua*_*uan 34 c++ templates partial-ordering c++11 template-argument-deduction

阅读C++ 11标准我无法完全理解以下语句的含义.例子非常受欢迎.

两组类型用于确定部分排序.对于涉及的每个模板,都有原始函数类型和转换后的函数类型.[注意:转换类型的创建在14.5.6.2中描述. - 结束注释]演绎过程使用变换后的类型作为参数模板,将另一个模板的原始类型用作参数模板.对于部分排序比较中涉及的每种类型,此过程完成两次:一次使用转换的模板-1作为参数模板,使用template-2作为参数模板,再次使用转换的模板-2作为参数模板和模板-1作为参数模板
- N3242 14.8.2.4.2

And*_*owl 56

虽然Xeo 在评论中给出了相当不错的描述,但我将尝试用一个有效的例子给出一步一步的解释.

首先,你引用的段落中的第一句话说:

对于涉及的每个模板,都有原始函数类型和转换后的函数类型.[...]

坚持下去,这个" 转换功能类型 "是什么?第14.5.6.2/3段解释说:

要生成转换模板,对于每种类型,非类型或模板模板参数(包括其模板参数包(14.5.3))分别合成唯一类型,值或类模板,并将其替换为该参数的每次出现在模板的功能类型[...]

这种正式的描述可能听起来模糊不清,但实际上它实际上非常简单.我们以此函数模板为例:

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

既然是TU类型参数,上面的段落要求我们为T(无论如何)选择相应的类型参数,并在T出现的函数签名中的任何地方替换它,然后执行相同的操作U.

现在" 合成一个独特的类型 "意味着你必须选择一个你没有在其他任何地方使用的虚构类型,我们可以调用它P1(然后选择一个P2for U),但这会使我们的讨论无用正式.

让我们只是简化事情,并挑选intTboolU-我们没有使用这些类型的其他地方,所以对于我们来说,他们只是一样好P1P2.

所以在转型之后,我们有:

void foo(int, bool) // #1b
Run Code Online (Sandbox Code Playgroud)

这是我们原始foo()函数模板的转换函数类型.

所以让我们继续解释你引用的段落.第二句话说:

演绎过程使用变换后的类型作为参数模板,将其他模板的原始类型作为参数模板.[...]

等等,什么" 其他模板 "?foo()到目前为止我们只有一个重载.是的,但为了在功能模板之间建立排序,我们至少需要其中两个,所以我们最好创建第二个.我们来使用:

template<typename T>
void foo(T const*, X<T>) // #2
Run Code Online (Sandbox Code Playgroud)

X我们的某些课程模板在哪里.

现在第二个功能模板是什么?啊,是的,我们需要做同样的事情,我们之前做的第一次重载foo()并转换它:所以再次,让我们选择一些类型参数T并替换T到处.我会选择char这个时间(在这个例子中我们没有在其他任何地方使用它,所以这和一些虚构的一样好P3):

void foo(char const*, X<char>) #2b
Run Code Online (Sandbox Code Playgroud)

太好了,现在他有两个函数模板和相应的转换函数类型.那么如何确定是否#1更专业,#2反之亦然?

我们从上面的句子中得知的是原始模板及其转换后的函数类型必须以某种方式匹配.但是怎么样?这就是第三句话的解释:

对于部分排序比较中涉及的每种类型,此过程完成两次:一次使用转换的模板-1作为参数模板,使用template-2作为参数模板,再次使用转换的模板-2作为参数模板和模板-1作为参数模板

所以基本上第一个模板()的转换函数类型#1b将与原始第二个模板(#2)的函数类型进行匹配.当然,反过来说,第二个第二个模板()的转换函数类型#2b将与原始第一个模板(#1)的函数类型进行匹配.

如果匹配将在一个方向上成功而在另一个方向上不成功,那么我们将知道其中一个模板比另一个模板更专业.否则,两者都不是更专业.

开始吧.首先,我们必须匹配:

void foo(int, bool) // #1b
Run Code Online (Sandbox Code Playgroud)

反对:

template<typename T>
void foo(T const*, X<T>) // #2
Run Code Online (Sandbox Code Playgroud)

有没有我们可以进行类型推演的方式T,使T const*成为准确intX<T>精确地变为bool?(实际上,完全匹配不是必需的,但是这个规则实际上很少有例外,它们与说明部分排序机制的目的无关,所以我们将忽略它们).

几乎不.所以让我们尝试相反的方式匹配.我们应该匹配:

void foo(char const*, X<char>) // #2b
Run Code Online (Sandbox Code Playgroud)

反对:

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

我们能推断TU在这里分别为char const*和产生精确匹配X<char>吗?当然!这是微不足道的.我们只是选择T = char const*U = X<char>.

所以我们发现第一次重载foo()(#1b)的转换函数类型不能与我们第二次重载foo()(#2)的原始函数模板匹配; 另一方面,第二个overload(#2b)的转换函数类型可以与第一个overload(#1)的原始函数模板匹配.

结论?第二次重载foo()比第一次更专业.

要选择一个反例,请考虑以下两个函数模板:

template<typename T, typename U>
void bar(X<T>, U)

template<typename T, typename U>
void bar(U, T const*)
Run Code Online (Sandbox Code Playgroud)

Which overload is more specialized than the other? I won't go through the whole procedure again, but you can do it, and that should convince you that a match cannot be produced in either direction, since the first overload is more specialized than the second one for what concerns the first parameter, but the second one is more specialized than the first one for what concerns the second parameter.

Conclusion? Neither function template is more specialized than the other.

Now in this explanation I have ignored a lot of details, exceptions to the rules, and cryptic passages in the Standard, but the mechanism outlined in the paragraph you quoted is indeed this one.

Also notice, that the same mechanism outlined above is used to establish a "more-specialized-than" ordering between partial specializations of a class template by first creating an associated, fictitious function template for each specialization, and then ordering those function templates through the algorithm described in this answer.

This is specified by paragraph 14.5.5.2/1 of the C++11 Standard:

For two class template partial specializations, the first is at least as specialized as the second if, given the following rewrite to two function templates, the first function template is at least as specialized as the second according to the ordering rules for function templates (14.5.6.2):

— the first function template has the same template parameters as the first partial specialization and has a single function parameter whose type is a class template specialization with the template arguments of the first partial specialization, and

— the second function template has the same template parameters as the second partial specialization and has a single function parameter whose type is a class template specialization with the template arguments of the second partial specialization.

Hope this helped.

  • 这是一个很好的答案,顺便说一句,太糟糕了,对于大多数C++程序员来说,过于复杂的东西,以产生更多的流量,相比之下,例如`vector :: resize()`问题:-) (6认同)
  • +1,但整个论证演绎游戏是在名字查找后出现的,只适用于函数重载/类特化,即它们都有相同的名称?所以`foo(T,U)`和`foo(T,X <T>)`会相互对战,对吗? (2认同)
  • 我还要提到的是,通过构造函数模板的一组唯一重载,然后继续应用“相互替换游戏”,可以解决针对类模板专业化的参数匹配。即,类专门化模式匹配与函数模板的自变量推导相同。 (2认同)