如何迭代参数包
How to Iterate over a parameter pack
我需要用 C++14 定义一个带有模板参数包的函数。
函数的调用者确保Args...
的大小必须是偶数,例如2,4,6...而我的函数将它们两个两个地传递给两个函数。
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... params) {
using params_t = std::tuple<Args...>;
auto tp = std::make_tuple(params...);
for (std::size_t i = 0; i < sizeof...(Args); ++i) {
f(std::get<i>(tp));
f2(std::get<++i>(tp));
}
}
// caller
func(f1, f2, "abc", 3, "def", "ppp");
这行不通,因为 i
不是常量表达式。
我能做什么?使用 std::tuple
迭代参数包是正确且唯一的方法吗?
要使用 std::tuple
迭代参数包,您通常会使用 std::index_sequence
引入新的索引包,并使用折叠表达式进行实际迭代。像这样:
template<typename F, typename F2, typename... Args, std::size_t... I>
void func_impl(F& f, F2& f2, std::tuple<Args...> params, std::index_sequence<I...>) {
// This would be a fold expression over a comma in C++17:
/*
(([&]{}(
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
)), ...);
*/
// C++14 version
using consume = int[];
(void) consume{ 0, [&]{
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
return 0;
}()... };
}
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... args) {
static_assert(sizeof...(args) % 2 == 0, "Must pass a multiple of 2 args to func");
func_impl(
f, f2,
std::forward_as_tuple(std::forward<Args>(args)...),
std::make_index_sequence<sizeof...(args) / 2>{}
);
}
但您也可以使用递归进行迭代,这在您的情况下可能更容易:
template<typename F, typename F2>
void func(F&& f, F2&& f2) {
// base case: do nothing
}
template<typename F, typename F2, typename Arg1, typename Arg2, typename... Args>
void func(F&& f, F2&& f2, Arg1&& arg1, Arg2&& arg2, Args&&... args) {
// recursive case
f(arg1);
f2(arg2);
func(std::forward<F>(f), std::forward<F2>(f2), std::forward<Args>(args)...);
}
我需要用 C++14 定义一个带有模板参数包的函数。
函数的调用者确保Args...
的大小必须是偶数,例如2,4,6...而我的函数将它们两个两个地传递给两个函数。
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... params) {
using params_t = std::tuple<Args...>;
auto tp = std::make_tuple(params...);
for (std::size_t i = 0; i < sizeof...(Args); ++i) {
f(std::get<i>(tp));
f2(std::get<++i>(tp));
}
}
// caller
func(f1, f2, "abc", 3, "def", "ppp");
这行不通,因为 i
不是常量表达式。
我能做什么?使用 std::tuple
迭代参数包是正确且唯一的方法吗?
要使用 std::tuple
迭代参数包,您通常会使用 std::index_sequence
引入新的索引包,并使用折叠表达式进行实际迭代。像这样:
template<typename F, typename F2, typename... Args, std::size_t... I>
void func_impl(F& f, F2& f2, std::tuple<Args...> params, std::index_sequence<I...>) {
// This would be a fold expression over a comma in C++17:
/*
(([&]{}(
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
)), ...);
*/
// C++14 version
using consume = int[];
(void) consume{ 0, [&]{
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
return 0;
}()... };
}
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... args) {
static_assert(sizeof...(args) % 2 == 0, "Must pass a multiple of 2 args to func");
func_impl(
f, f2,
std::forward_as_tuple(std::forward<Args>(args)...),
std::make_index_sequence<sizeof...(args) / 2>{}
);
}
但您也可以使用递归进行迭代,这在您的情况下可能更容易:
template<typename F, typename F2>
void func(F&& f, F2&& f2) {
// base case: do nothing
}
template<typename F, typename F2, typename Arg1, typename Arg2, typename... Args>
void func(F&& f, F2&& f2, Arg1&& arg1, Arg2&& arg2, Args&&... args) {
// recursive case
f(arg1);
f2(arg2);
func(std::forward<F>(f), std::forward<F2>(f2), std::forward<Args>(args)...);
}