【问题标题】:How iteration over parameter pack going through initializer_list?如何通过 initializer_list 对参数包进行迭代?
【发布时间】:2022-01-22 03:51:48
【问题描述】:

抱歉,我的问题含糊不清,但我只是不明白这个函数的作用和方式。来自here的代码:

template<typename ... T>
auto sum (T ... t)
{
    typename std::common_type<T...>::type result{}; //zero-initialization?
    (void)std::initializer_list<int>{(result += t, 0)...}; //why 0 is here
    return result;
}

我不知道为什么,但是这段代码看起来很奇怪,在我看来它不像 C++。从语义上讲,这个函数显然将结果变量中的所有参数相加。但我完全不明白为什么要这样写。在此处使用 initializer_list 似乎是触发对参数包中的参数进行迭代的技巧,但仍然...

为什么 initializer_list 被明确地强制转换为 void?不占用额外内存?

参数包的迭代是如何进行的?为什么不呢,比如(void)std::initializer_list&lt;int&gt;{(result += t)...};(顺便说一下它不会编译)。

【问题讨论】:

  • 在 C++17 发明 fold expressions 之前,这个技巧很常见。现在,你可以写return (... + t); 在此之前,包扩展只能出现在某些上下文中,例如在大括号初始化列表中。因此,要对包执行计算,您安排了一个虚拟大括号初始化列表,其中每个初始化程序都有您想要的副作用。初始化器的值无关紧要,只有它的副作用。 (result += t, 0) 使用逗号运算符 - 它表示“评估 result += t,然后生成整数 0 作为值”。
  • 强制转换为 void 是为了避免某些编译器对未使用的表达式发出警告。
  • std::initializer_list&lt;int&gt;{(result += t)...}; 无法编译可能是因为(result += t) 不是int 类型或不能转换为int。相比之下,(result += t, 0) 的类型始终是0 的类型,即int

标签: c++ variadic-templates variadic-functions


【解决方案1】:

感谢cmets,我找到了答案。

我从来没有遇到过逗号运算符,所以 (result += t, 0) 行对我来说毫无意义,直到您的 cmets 关于逗号运算符和 this question 的存在。所以基本上我们用零初始化我们的列表。而且由于我为整数创建了 initializer_list 类型,所以我不能写 (void)std::initializer_list&lt;int&gt;{result += t...},因为 result += t 的返回值是 int&amp; 而不是 int

那么我们为什么不写(void)std::initializer_list&lt;int&amp;&gt;{result += t...}?它无法编译,我怀疑是因为array of references is forbidden in C++。所以这是我的问题的解决方案:

template <typename ... T>
auto sum1(T ... t)
{
    std::common_type_t<T...> tmp{};
    std::initializer_list<std::reference_wrapper<std::common_type_t<T...>>>{tmp += t...};
    return tmp;
}

【讨论】:

  • “我不能写……因为 result += t 的返回值是 int&amp; 而不是 int 不,你至少可以这样写如果resultint 类型。 “这就是我的问题的解决方案” 解决什么问题?问题中的代码不起作用吗?
猜你喜欢
  • 2016-01-08
  • 1970-01-01
  • 1970-01-01
  • 2016-10-22
  • 2021-04-18
  • 2017-12-03
  • 2017-06-15
  • 1970-01-01
  • 2015-03-23
相关资源
最近更新 更多