问答的接受的答案可变模板包扩展利用常见的C++17之前(折叠表达式之前)的方法来“折叠”未扩展的模板参数包。
我见过这种技术的几种不同变体;以上面的问答为例:
#include <initializer_list>
#include <iostream>
#include <utility>
template <typename T> static void bar(T) {}
template <typename... Args> static void foo1(Args &&... args) {
using expander = int[];
// Left-most void to avoid `expression result unused [-Wunused-value]`
(void)expander{0, ((void)bar(std::forward<Args>(args)), 0)...};
}
template <typename... Args> static void foo2(Args &&... args) {
int dummy[] = {0, ((void)bar(std::forward<Args>(args)), 0)...};
// To avoid `unused variable 'dummy' [-Wunused-variable]`
(void)dummy;
}
template <typename... Args> static void foo3(Args &&... args) {
// Left-most void to avoid `expression result unused [-Wunused-value]`
(void)std::initializer_list<int>{((void)bar(std::forward<Args>(args)), 0)...};
}
template <typename... Args> static void foo4(Args &&... args) {
auto l = {0, ((void)bar(std::forward<Args>(args)), 0)...};
// To avoid `unused variable 'l' [-Wunused-variable]`
(void)l;
}
int main() {
foo1(1, 2, 3, "3");
foo1();
foo2(1, 2, 3, "3");
foo2();
foo3(1, 2, 3, "3");
foo3();
foo4(1, 2, 3, "3");
foo4();
return 0;
}
这些变体(或其他变体)是否被视为“惯用的变体”?它们之间是否有任何需要注意的微妙/差异?
std::initializer_list
方法不需要braced-init-list中有点难以捉摸的最左边的
0
,因为初始化列表可能为空,而数组的大小可能不是零(/负)。也许这可能是 foo3
的一个论据(可以说,以额外的 #include
为代价,稍微降低了复杂性)。
这些变体(或其他变体)是否被视为“惯用的变体”?
我会说是的。
它们之间是否有任何需要注意的微妙/差异?
大部分是等价的,但是
foo3
和 foo4
需要 #include <initializer_list>
foo1
和 foo2
则不然。