"Folding" C++17 之前的模板参数包:惯用方法
"Folding" of template parameter packs in pre C++17: idiomatic approach
C++11 和 C++14 中的折叠表达式:惯用方法?
accepted answer of the Q&A Variadic template pack expansion 对未扩展模板参数包的 "folding" 使用常见的 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;
}
是否考虑了这些变体(或其他变体)"the idiomatic one"?他们之间有什么subtleties/differences需要注意的吗?
std::initializer_list
方法不需要 braced-init-list 中有点难以捉摸的最左边的 0
,因为初始化列表可能是空,而数组可能不是零(/负)大小。可能这可能是 foo3
的一个论据(可以说以额外的 #include
为代价稍微降低了复杂性)。
Are any of these variations (or other variations) considered "the idiomatic one"?
我会说是的。
Are there any subtleties/differences between them that one would need to take care with?
大部分都是等价的,但是
foo3
和 foo4
需要 #include <initializer_list>
而 foo1
和 foo2
则不会。
C++11 和 C++14 中的折叠表达式:惯用方法?
accepted answer of the Q&A Variadic template pack expansion 对未扩展模板参数包的 "folding" 使用常见的 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;
}
是否考虑了这些变体(或其他变体)"the idiomatic one"?他们之间有什么subtleties/differences需要注意的吗?
std::initializer_list
方法不需要 braced-init-list 中有点难以捉摸的最左边的 0
,因为初始化列表可能是空,而数组可能不是零(/负)大小。可能这可能是 foo3
的一个论据(可以说以额外的 #include
为代价稍微降低了复杂性)。
Are any of these variations (or other variations) considered "the idiomatic one"?
我会说是的。
Are there any subtleties/differences between them that one would need to take care with?
大部分都是等价的,但是
foo3
和 foo4
需要 #include <initializer_list>
而 foo1
和 foo2
则不会。