阅读C 11标准,我无法完全理解以下陈述的含义。榜样是非常受欢迎的。
两组类型用于确定偏序。对于涉及的每个模板,都有原始函数类型和转换后的函数类型。[注:转换类型的创建在14.5.6.2.-结束注]演绎过程使用转换类型作为参数模板,另一个模板的原始类型作为参数模板。对于偏序比较中涉及的每种类型,此过程执行两次:一次使用转换后的模板-1作为参数模板,模板-2作为参数模板,再次使用转换后的模板-2作为参数模板,模板-1作为参数模板
--N3242 14.8.2.4.2
虽然Xeo在评论中给出了很好的描述,但我将尝试用一个工作示例一步一步地解释。
首先,你引用的段落的第一句话说:
对于涉及的每个模板,都有原始函数类型和转换后的函数类型。[...]
等等,这个“转换函数类型”是什么?第14.5.6.2/3段解释如下:
为了生成转换后的模板,对于每个类型、非类型或模板模板参数(包括其模板参数包(14.5.3)),分别合成一个唯一的类型、值或类模板,并将其替换为模板函数类型中该参数的每次出现[...]
这种形式上的描述听起来可能有些模糊,但实际上非常简单。我们以这个函数模板为例:
template<typename T, typename U>
void foo(T, U) // #1
既然T
和U
是类型参数,上面的段落要求我们为T
(无论什么)选择一个相应的类型参数,并在出现T
的函数签名中的任何地方替换它,然后对U
执行同样的操作。
现在“合成一个独特的类型”意味着你必须选择一个你在其他任何地方都没有使用过的虚构类型,我们可以称之为P1
(然后为U
选择一个P2
),但这将使我们的讨论变得毫无意义。
让我们把事情简化一下,为T
选择int
,为U
选择bool
——我们没有在其他任何地方使用这些类型,因此就我们的目的而言,它们与P1
和P2
一样好。
因此,在转型之后,我们有:
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*
变成int
和X
几乎不那么让我们试着反过来匹配。我们应该匹配:
void foo(char const*, X<char>) // #2b
反对:
template<typename T, typename U>
void foo(T, U) // #1
我们能在这里推断出
T
和U
来产生一个完全匹配的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中的模板类是什么?它们是一种特殊的设计模式还是什么? 提前谢谢你。