template<typename T>
struct Test{};
template<typename T>
struct Test<T&&>{};
考虑上面的例子,标准说类模板的部分专业化应该比它的主要类模板更专业化。
在类模板部分专业化的参数列表中,适用以下限制:
专业化应比主模板更专业。
要确定哪个更专业,将对其应用以下规则:
对于两个类模板的部分专业化,如果对两个函数模板进行以下重写,根据函数模板的排序规则,第一个函数模板比第二个更专业化:
- 这两个函数模板中的每一个都具有与相应的部分专门化相同的模板参数
- 每个函数模板都有一个函数参数,其类型是类模板专用化,其中模板参数是部分专用化的简单模板id的模板参数列表中每个模板参数的函数模板的相应模板参数
对于主类模板,重写的函数模板如下所示:
template<typename T> void ordering(Test<T>)
类模板部分专业化的重写函数模板是这样的:
template<typename T> void ordering(Test<T&&>)
根据";在部分排序期间推导模板参数":
用于确定排序的类型取决于执行部分排序的上下文:
- 在函数调用的上下文中,使用的类型是函数调用具有参数的函数参数类型
- 在调用转换函数的上下文中,将使用转换函数模板的返回类型
- 在其他上下文中,使用函数模板的函数类型
上面从参数模板中指定的每个类型以及参数模板中的相应类型都被用作p和A的类型。如果特定p不包含参与模板参数推导的模板参数,则该p不用于确定排序。
function call
和call to a conversion function
都不是此上下文。所以子弹头3起作用了。即取void(Test<T>)
为P,取void(Test<T&&>)
为A,反之亦然。对于这对p/A,它是在温度扣除类型#10中提到的情况,即
将p的各个参数类型列表([dcl.fct])的每个参数类型pi与A
模板参数可以在几种不同的上下文中推导出来,但在每种情况下,都会将根据模板参数指定的类型(称为p)与实际类型(称其为a)进行比较,并试图找到模板参数值(类型参数的类型、非类型参数的值或模板参数的模板),该模板参数值将使P在替换推导的值(称之为推导的a)后与a兼容。
这里,我们在每个函数类型中只有一个参数。因此,将
Test<T>
与Test<T&&>
进行比较,反之亦然,在temp.dexpract.type#9中提到了这样的过程。然而,我认为,标准中没有相关规则来说明比较过程的细节。换句话说,为什么我们可以从
T&&
推导出T
(T将是T&&
),但不能反过来。如果我错过了关于细节的相关规则,请指出。如果标准中确实没有这样的详细描述,我在哪里可以找到关于模板论证推导过程细节的相关技术?
在我看来,你所引用的内容是你所关注的内容中的一个问题,但它已经被注意到并修复了。特别是,您引用以下内容:
上面从参数模板中指定的每个类型以及参数模板中相应的类型都被用作p和A的类型。如果特定的p不包含参与模板参数推导的模板参数,则该p不用于确定排序。
到N4800(可能之前——我还没有确切地追踪到这是什么时候改变的),这已经被改变为以下内容(§[temp.dexer.partial]/4,5):
4上面从参数模板指定的每个类型和从参数模板中指定的相应类型都被用作p和A的类型。
5在进行偏序之前,对用于偏序的类型执行某些转换:
(5.1)--如果p是引用类型,P由所引用的类型替换。
(5.2)--如果A是引用类型,则A由所引用类型替换。
这有效地消除了将T推导为引用类型的可能性,因为推导T的类型永远不可能是引用。
在[temp.dexeract.call]和[temp.decheract.conv]中,它提到
通常,推导过程会尝试查找模板参数将使推导出的A与A.相同的值
我相信这条规则是众所周知的,所以在其他子条款中没有提及(在上述两个子条款中提到了它,因为这两个子条款有例外)。