g++、clang++和MSVC (2018年前)都使用了以下C++17代码,从而生成输出"unsigned“然后是" int”:
#include <iostream>
void print_type(int) { std::cout << "int\n"; }
void print_type(unsigned int) { std::cout << "unsigned int\n"; }
template <typename ...T>
void print_types(T ...args)
{
(print_type(args),...);
}
int main()
{
print_types<unsigned int>(1, 1);
}我同意这应该是这样的,但是我很难在标准中找到一个关于为什么和如何的描述。
首先,在执行其余的模板参数推导之前,有一个描述显式模板参数处理过程的tem.deduction/2:
在计算给定函数模板的显式指定模板参数列表时,将执行以下步骤:
在这个例子中,unsigned int肯定是一个“指定的模板参数值”。但是,如果它的“相应的模板参数”T现在被替换,那么很难看出它以后会变成一个更长的类型列表。
对于模板参数演绎过程,有tem.扣减.there/1:
对于在参数-声明列表结尾处出现的函数参数包,将对调用的每个剩余参数执行演绎,将函数参数包的声明符-id的类型
P作为对应的函数模板参数类型。每个扣减都会为由函数参数包展开的模板参数包中的后续位置推导模板参数。
在这里,我将“调用的剩余参数”作为后面的参数,这些参数对应于非最终函数参数包的函数参数。但这意味着,在我的示例中,第一个函数参数1用于推断T=int。这种推断是否真的发生了,但随后被T=unsigned int从显式模板参数中丢弃/重写了?
或者“调用的剩余参数”应该是指与最终函数参数包不相对应的函数参数,以及与显式模板参数生成的参数类型相对应的参数类型之后的函数参数;“函数参数包扩展的模板参数包中的后续位置”应该是指在任何由显式模板参数填充后的顺序位置,但这一点还不清楚。如果是这样的话,还有一个与函数参数包相关联的参数类型列表,但它仍然是一个函数参数包。
给出预期行为的另一个可能的实现是:当一个或多个显式模板参数A_1,.,A_k对应于模板参数pack P,发明另一个相同类型的模板参数包More_P,并用模板参数列表{A_1、.、A_k、More_P...}替换P的每个扩展。然后可以像其他模板参数包一样推导More_P。如果从来没有推导过More_P,那么在计算语义之前,用一个空列表代替它的所有扩展,就像计算所有其他推导的替换一样。但在“标准”中,这种解释的理由就更少了。
我是否遗漏了更好地描述显式模板参数和导出的模板参数如何协同工作以形成一个模板参数包的单个列表的一些内容?
发布于 2018-07-14 15:16:53
是[temp.arg.explicit]/8
模板参数演绎可以扩展模板参数包对应的模板参数序列,即使序列包含显式指定的模板参数。 示例: template空洞f(类型.值);void (){ f(0,0,0);//类型被推导为序列int*,float*,int } - end示例
https://stackoverflow.com/questions/51340237
复制相似问题