模板参数推导过程的细节是什么?

4
template<typename T>
struct Test{};

template<typename T>
struct Test<T&&>{};

考虑上面的例子,标准规定类模板偏特化应比其主类模板更加专业化。
在类模板偏特化的参数列表中,应遵守以下限制:
该特化应比主模板更加专业化。
为了确定哪个更加专业化,将对它们应用以下规则:
对于两个类模板的部分特化,如果给出以下重写到两个函数模板,则第一个函数模板根据函数模板排序规则比第二个更加专业化:
每个两个函数模板都有与对应的部分特化相同的模板参数。
每个函数模板都具有单个函数参数,其类型是一个类模板特化,其中模板参数是从函数模板的每个模板参数中获取的,这些模板参数包含在部分特化的simple-template-id的模板参数列表中。
对于主类模板,重写的函数模板将如下所示:
template<typename T>
void ordering(Test<T>)

而类模板部分特化的重写函数模板应该像这样:

template<typename T>
void ordering(Test<T&&>)

根据“在部分排序期间推导模板参数”的规则:
用于确定排序的类型取决于执行部分排序的上下文环境:
- 在函数调用的上下文环境中,使用函数参数类型作为类型,该函数调用具有参数。 - 在调用转换函数的上下文环境中,使用转换函数模板的返回类型。 - 在其他上下文中使用函数模板的函数类型。
从参数模板中提名的每个类型和来自参数模板的相应类型都用作P和A的类型。如果特定的P不包含参与模板参数推导的模板参数,则不使用该P来确定排序。
既不是“函数调用”也不是“调用转换函数”的上下文环境。因此,第3个项目适用。这意味着以void(Test<T>)作为P,以void(Test<T&&>)作为A,反之亦然。
对于这个P/A对,它是在temp.deduct.type#10中提到的情况,也就是说,
每个参数类型Pi在相应的参数类型列表([dcl.fct])中与相应参数类型列表A的Ai进行比较。
在几种不同的上下文中可以推导模板参数,但在每种情况下,将以模板参数为基础指定的类型(称之为P)与实际类型(称之为A)进行比较,并尝试找到模板参数值(类型参数的类型,非类型参数的值或模板参数的模板),使得在替换推导出的值(称之为推导出的A)后,P与A兼容。
在这里,每个函数类型只有一个参数。因此将Test<T>Test<T&&>进行比较,反之亦然,在temp.deduct.type#9中提到了这个过程。
但是我在这里认为标准中没有相关规则说明比较过程的细节。换句话说,为什么我们可以从T&&推导出T(T将成为T&&),但反过来不行。如果我错过了相关规则的细节,请指出。如果标准确实没有这样的详细描述,那么在哪里可以找到有关模板参数推导过程细节的相关技术?
2个回答

1
我认为你引用的是你所看到的问题,但它已经被注意并解决了。特别地,你引用了以下内容:
从参数模板中提名的每个类型和对应的来自参数模板的类型都被用作P和A的类型。如果某个P不包含参与模板参数推断的模板参数,则不使用该P来确定排序。
根据N4800(也可能在此之前 - 我还没有追踪确切的更改时间),这已更改为以下内容(§[temp.deduct.partial]/4, 5):
从参数模板中提名的每个类型和对应的来自参数模板的类型都被用作P和A的类型。 在进行部分排序之前,对用于部分排序的类型执行某些转换: (5.1)- 如果P是引用类型,则将P替换为所引用的类型。 (5.2)- 如果A是引用类型,则将A替换为所引用的类型。
这有效地消除了将T推导为引用类型的可能性,因为推导出它的类型永远不可能是引用类型。

你能否提供你引用的更改内容的链接?我会去看一下。 - xmh0511
@jackX:我看了一下[temp.deduct.partial]/4(和5)。 - Jerry Coffin
@jackX:这是N4800,如果你需要帮助的话(但我建议下载一份副本,而不是在线查看)。 - Jerry Coffin
那个规则在我在问题中提到的标准版本中仍然存在。在我的问题中,Pvoid(Test<T&&>) 或者 void(Test<T>),该规则并没有说我们可以删除模板参数列表中出现的引用。该规则的含义实际上是说,如果 PTest<T>&&,那么在部分排序之前,它应该转换为 Test<T> - xmh0511

1
在 [temp.deduct.call] 和 [temp.deduct.conv] 中提到,通常情况下,推断过程试图找到模板参数值,使得被推导出的 A 与 A 相同。我认为这个规则是众所周知的,因此在其他子条款中没有提到(在上述两个子条款中提到,因为这两个子条款中有例外)。

问题是如何找到模板参数值,使推断出的 A 与给定的 A 相同。这个细节在标准中没有提到。 - xmh0511
@jackX,“如何”并不重要。我们只关心结果,即如果存在一种类型使得推导出的A与A相同,则该类型是推导出的类型;否则推导失败。 - xskxzr
@xskzr 这确实是一个问题。例如,从 T* 推导出 T,我们可以找到 T* 对应的 T,但反过来却不行,为什么呢?这个细节在标准中没有写明。 - xmh0511
@sxkxzr 我知道这一点。但我在这里争论的是,当给定A作为int*时,当P是int时,P*A相同。我的意思是,标准没有说明当我们有一个P/A对时,我们将遵守什么规则来找到这些模板参数值。或者只是不能使它们相等的形式。为什么T可以接受任何类型? - xmh0511
让我们在聊天中继续这个讨论 - xskxzr
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接