当前位置: 首页 > 知识库问答 >
问题:

模板推导中的偏序程序是什么

郑博
2023-03-14

阅读C 11标准,我无法完全理解以下陈述的含义。榜样是非常受欢迎的。

两组类型用于确定偏序。对于涉及的每个模板,都有原始函数类型和转换后的函数类型。[注:转换类型的创建在14.5.6.2.-结束注]演绎过程使用转换类型作为参数模板,另一个模板的原始类型作为参数模板。对于偏序比较中涉及的每种类型,此过程执行两次:一次使用转换后的模板-1作为参数模板,模板-2作为参数模板,再次使用转换后的模板-2作为参数模板,模板-1作为参数模板
--N3242 14.8.2.4.2

共有1个答案

卢书
2023-03-14

虽然Xeo在评论中给出了很好的描述,但我将尝试用一个工作示例一步一步地解释。

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

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

等等,这个“转换函数类型”是什么?第14.5.6.2/3段解释如下:

为了生成转换后的模板,对于每个类型、非类型或模板模板参数(包括其模板参数包(14.5.3)),分别合成一个唯一的类型、值或类模板,并将其替换为模板函数类型中该参数的每次出现[...]

这种形式上的描述听起来可能有些模糊,但实际上非常简单。我们以这个函数模板为例:

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

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

现在“合成一个独特的类型”意味着你必须选择一个你在其他任何地方都没有使用过的虚构类型,我们可以称之为P1(然后为U选择一个P2),但这将使我们的讨论变得毫无意义。

让我们把事情简化一下,为T选择int,为U选择bool——我们没有在其他任何地方使用这些类型,因此就我们的目的而言,它们与P1P2一样好。

因此,在转型之后,我们有:

void foo(int, bool) // #1b

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

让我们继续解释你引用的段落。第二句说:

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

等等,什么“其他模板”?到目前为止,我们只有一个超负荷的foo()。是的,但是为了在函数模板之间建立排序,我们至少需要两个,所以我们最好创建第二个。让我们使用:

template<typename T>
void foo(T const*, X<T>) // #2

其中X是我们的一些类模板。

第二个函数模板是什么?啊,是的,我们需要像之前一样对foo()的第一个重载执行相同的操作并对其进行转换:因此,再次,让我们为T选择一些类型参数并替换T。这次我将选择char(在本例中,我们没有在其他任何地方使用它,因此这与一些虚构的P3)一样好:

void foo(char const*, X<char>) #2b

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

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

对于偏序比较中涉及的每种类型,此过程执行两次:一次使用转换模板-1作为参数模板,模板-2作为参数模板,另一次使用转换模板-2作为参数模板,模板-1作为参数模板

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

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

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

void foo(int, bool) // #1b

反对:

template<typename T>
void foo(T const*, X<T>) // #2

有没有一种方法可以在T上执行类型推导,使T const*变成intX

几乎不那么让我们试着反过来匹配。我们应该匹配:

void foo(char const*, X<char>) // #2b

反对:

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

我们能在这里推断出TU来产生一个完全匹配的char const*X吗

因此,我们发现第一个重载的foo()#1b)的转换函数类型无法与第二个重载的foo()#2)的原始函数模板相匹配;另一方面,第二个重载(#2b)的转换函数类型可以与第一个重载(#1)的原始函数模板相匹配。

结论foo()的第二个重载比第一个重载更专业化。

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

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

template<typename T, typename U>
void bar(U, T const*)

哪个重载比另一个重载更专业?我将不再重复整个过程,但您可以这样做,这应该会让您相信,在两个方向上都不能生成匹配,因为第一个重载比第二个重载对第一个参数更专业,但第二个重载比第一个重载对第二个参数更专业。

结论两个函数模板都不比另一个更专业。

在这个解释中,我忽略了很多细节,规则的例外,以及标准中的神秘段落,但是你引用的段落中概述的机制确实是这个。

还请注意,上面概述的相同机制用于通过首先为每个专门化创建一个关联的、虚构的函数模板,然后通过本答案中描述的算法对这些函数模板进行排序,从而在类模板的部分专门化之间建立一个“更专门化”的排序...

C 11标准第14.5.5.2/1段对此进行了规定:

对于两个类模板部分专门化,如果根据函数模板的排序规则(14.5.6.2),给定对两个函数模板的以下重写,第一个函数模板至少与第二个函数模板一样专门化,则第一个函数模板至少与第二个函数模板一样专门化:

-第一个函数模板具有与第一个局部特化相同的模板参数,并且具有单个函数参数,其类型是具有第一个局部特化的模板参数的类模板特化

-第二个函数模板具有与第二个部分专门化相同的模板参数,并且具有一个单一的函数参数,其类型是具有第二个部分专门化的模板参数的类模板专门化。

希望这有帮助。

 类似资料:
  • 有一个模态代码。来自Twitter引导的js: 什么是role=“dialog”aria labelledby=“myModalLabel”aria hidden=“true”? 它到底做什么?

  • 我正在学习自动模板演绎guid:https://en.cppreference.com/w/cpp/language/class_template_argument_deduction.因此我想试试这个。 我有以下嵌套类结构,其中是一个带有非模板参数的模板化类,内部结构只是有一个 我有< code > MyStruct mStruct作为会员: 我想像这样实现或构建My类 因此我给出了如上的演绎g

  • 另一个有用的可能示例:(伪代码)

  • std=C14的g在函子类的模板方法(本身不是模板)上给我一个“无法推断模板参数'Key'”错误。我不知道为什么。代码看起来应该可以工作。 我正在实现一个2-3树,它有一个采用函子的层次顺序遍历方法。操作人员tree23代码基本上是这样的: 级别顺序遍历调用仿函数的函数调用操作符,向其传递两个参数。 函子非常简单:

  • 程序是说明如何执行一个计算的一组指令序列。计算既可以是数学运算(如求解方程组或者找出多项式的根),也可以是符号运算(如搜索和替换文档中的文本,甚至是编译一个程序)。 不同编程语言中的指令(或者说命令、语句)看起来是不同的,但每种语言都有下面几个基本功能: 输入:从键盘、文件或其他设备获取数据。 输出:在屏幕上显示数据,将数据发送给文件或其他设备。 数学运算:执行基本的数学操作,比如加法和乘法。 测

  • 我是Java新手。我只做了大约一年的编程。Spring使用模板是什么意思?在Spring,有jdbc模板、jms模板等。。java中的模板类是什么?它们是一种特殊的设计模式还是什么? 提前谢谢你。