虽然 Xeo在评论中给出了很好的描述,但我将尝试通过一个工作示例进行逐步解释。
首先,您引用的段落的第一句话说:
对于涉及的每个模板,都有原始函数类型和转换后的函数类型。[...]
等等,这个“转换函数类型”是什么?第 14.5.6.2/3 段解释说:
为了生成转换后的模板,对于每个类型、非类型或模板模板参数(包括其模板参数包 (14.5.3)),分别合成唯一的类型、值或类模板,并将其替换为该参数的每次出现在模板的函数类型中 [...]
这种形式的描述可能听起来晦涩难懂,但在实践中它实际上非常简单。我们以这个函数模板为例:
template<typename T, typename U>
void foo(T, U) // #1
现在因为T
andU
是类型参数,上面的段落要求我们为T
(whatever) 选择一个对应的类型参数,并在函数签名中出现的任何地方替换它T
,然后对U
.
现在“合成一个独特的类型”意味着你必须选择一个你没有在其他地方使用过的虚构类型,我们可以称之为P1
(然后选择一个P2
for U
),但这会使我们的讨论变得毫无用处。
让我们简化一些事情并选择int
forT
和bool
for - 我们不会在其他任何地方使用这些类型,因此出于我们的目的,它们与andU
一样好。P1
P2
所以在转换之后,我们有:
void foo(int, bool) // #1b
这是我们原始foo()
函数模板的转换函数类型。
因此,让我们继续解释您引用的段落。第二句话说:
推演过程使用转换后的类型作为参数模板,将另一个模板的原始类型作为参数模板。[...]
等等,什么“其他模板”?foo()
到目前为止,我们只有一个过载。是的,但是为了建立函数模板之间的顺序,我们至少需要其中两个,所以我们最好再创建一个。让我们使用:
template<typename T>
void foo(T const*, X<T>) // #2
X
我们的一些类模板在哪里。
那么第二个函数模板呢?啊,是的,我们需要像之前对第一个重载 offoo()
和转换它所做的一样:所以再一次,让我们选择一些类型参数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<T>
变得准确bool
?(实际上,完全匹配不是必需的,但是这条规则确实很少有例外,并且它们与说明偏序机制的目的无关,因此我们将忽略它们)。
几乎不。所以让我们尝试反过来匹配。我们应该匹配:
void foo(char const*, X<char>) // #2b
反对:
template<typename T, typename U>
void foo(T, U) // #1
我们可以推导出T
和来分别为和U
产生精确匹配吗?当然!这是微不足道的。我们只选择和。char const*
X<char>
T = char const*
U = X<char>
所以我们发现我们第一次重载的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):
— 第一个函数模板具有与第一个部分特化相同的模板参数,并且具有一个函数参数,其类型是具有第一个部分特化的模板参数的类模板特化,并且
— 第二个函数模板具有与第二个偏特化相同的模板参数,并且具有一个函数参数,其类型是具有第二个偏特化的模板参数的类模板特化。
希望这有帮助。