可变参数模板查询

Variadic template queries

我正在尝试理解下面的代码。直接从 Jason Turner youtube 视频复制

#include <iostream>
#include <sstream>
#include <vector>

template<typename ...T>
std::vector<std::string> print(const T& ...t)
{
    std::vector<std::string> retval;
    std::stringstream ss;
    (void)std::initializer_list<int>{
      (
         ss.str(""),
         ss << t,
         retval.push_back(ss.str()),
         0)...
    };
    return retval;
}

int main()
{
    for( const auto &s : print("Hello", "World", 5.4, 1.1, 2.2) ) {
        std::cout << s << "\n";
    }
}

问题:

  1. 有人可以给出 initializer_list 中代码的扩展视图吗?我很难想象语句是如何扩展每个参数的? ss.str(""), ss << t 然后 push_back 是针对包中的每个参数发生还是只执行一次?我无法想象扩展的初始化列表会是什么样子?
  2. 为什么我们需要 initializer_list 末尾的虚拟“0”?如果我没有那个会怎样?
  3. 如何轻松查看共享代码中的...扩展?

Tt参数包.

有两种使用包的主要方式:折叠表达式(在 C++17 和更新版本中)和常规包扩展。

A fold expression 看起来像这样:

((ss.str(""), ss << t, retval.push_back(ss.str())), ...);

折叠表达式为每个包元素重复其操作数,在属于每个参数的部分之间插入一些运算符(在本例中为 ,)。上面的扩展为:

((ss.str(""), ss << t1, retval.push_back(ss.str())), // <-- Inserted commas
 (ss.str(""), ss << t2, retval.push_back(ss.str())), // <--
 (ss.str(""), ss << t3, retval.push_back(ss.str())));

常规扩展类似,只是它总是生成逗号,并且逗号不能是运算符(与数组初始值设定项或函数之间的分隔符相反)参数)。

例如如果您假设 (ss.str(""), ss << t, retval.push_back(ss.str()))...; 会像折叠表达式一样工作,那么它就不会工作,因为生成的逗号必须是一个运算符。

由于这个限制,在 C++17 之前人们使用虚拟数组(或像您的示例中的 initializer_lists)。这是使用数组时的样子:

int dummy[] = {(ss.str(""), ss << t, retval.push_back(ss.str()), 0)...};

扩展为:

int dummy[] = {(ss.str(""), ss << t1, retval.push_back(ss.str()), 0),
               (ss.str(""), ss << t2, retval.push_back(ss.str()), 0),
               (ss.str(""), ss << t3, retval.push_back(ss.str()), 0)};

此处,数组(或initializer_list)的大小与包的大小匹配。

,0是必需的,因为每个数组元素都是一个int,所以必须用int.

初始化