c++ - 模板参数包如何同时具有显式参数和推导参数?

标签 c++ language-lawyer variadic-templates c++17

g++、clang++ 和 MSVC(2018 年之前)全部 accept以下 C++17 代码,导致输出“unsigned int”,然后是“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);
}

我同意这应该以这种方式工作,但我很难在标准中找到原因和具体方式的描述。

首先,[temp.deduct]/2 描述了在执行其余模板参数推导之前对显式模板参数的处理:

[T]he following steps are performed when evaluating an explicitly specified template argument list with respect to a given function template:

  • ... There must not be more arguments than there are parameters unless at least one parameter is a template parameter pack, and there shall be an argument for each non-pack parameter....

  • The specified template argument values are substituted for the corresponding template parameters as specified below.

在示例中,unsigned int当然是“指定的模板参数值”。但如果其“对应模板参数”T现在被替换了,很难看出它以后会如何变成一个更长的类型列表。

对于模板参数推导过程,有[temp.deduct.call]/1:

For a function parameter pack that occurs at the end of the parameter-declaration-list, deduction is performed for each remaining argument of the call, taking the type P of the declarator-id of the function parameter pack as the corresponding function template parameter type. Each deduction deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack.

这里的“调用的剩余参数”是指与不是最终函数参数包的函数参数对应的参数之后的参数。但这意味着在我的示例中,第一个函数参数 1用于推导T=int 。这种推论是否确实发生,但随后被 T=unsigned int 丢弃/覆盖?来自显式模板参数?

或者也许“调用的剩余参数”应该是指那些不对应于最终函数参数包的函数参数之后以及与从显式模板参数生成的参数类型相对应的函数参数;并且“由函数参数包扩展的模板参数包中的后续位置”应该是指在由显式模板参数填充的任何位置之后的连续位置,但这还很不清楚。如果是这样,那么令人困惑的是,有一个与函数参数包关联的参数类型列表,但它仍然是一个函数参数包。

[给出预期行为的另一种可能的实现是:当一个或多个显式模板参数 A_1 时, ..., A_k对应模板参数包P ,发明另一个模板参数包More_P同类,并替换 P 的每个扩展使用模板参数列表 { A_1 , ..., A_k , More_P... }。然后More_P可以像任何其他模板参数包一样推导。如果More_P永远不会被推导,在评估所有其他推导的替换的语义之前,用空列表替换它的所有扩展。但标准中这种解释的理由就更少了。]

我是否错过了标准中的一些内容,这些内容更好地描述了显式模板参数和推导模板参数如何协同工作以形成一个模板参数包的单个列表?

最佳答案

这是 [temp.arg.explicit]/8 :

Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments. [ Example:

template<class ... Types> void f(Types ... values);

void g() {
  f<int*, float*>(0, 0, 0);     // Types is deduced to the sequence int*, float*, int
}

— end example ]

关于c++ - 模板参数包如何同时具有显式参数和推导参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51340237/

相关文章:

c++ - 在跨 dll/so 的注入(inject)类中使用异常是否安全?

javascript - for ... in - 正在迭代的对象是否在进入循环之前仅评估一次?

c++ - 以下 Variadic 模板行为是否不一致?

c++ - 链表和文件 I/O C++

c++ - 缓存友好顶点定义

c++ - C 中的 OpenSSL : after second decryption in application run, 结果的前 16 个字节是垃圾

c - 整数常量指向的对象的默认类型

c++ - 向上转换空指针是否会导致未定义的行为

c++ - 试图将一个函数从一个类传递给一个可变参数模板函数

c++ - 使用元编程的高效索引计算