C ++模板化包,折叠两次
C++ templated packs, fold twice
我已经阅读了一些类似的问题,但我没有找到我正在寻找的确切内容。
以纯数学方式,列表被递归定义为:(head, rest)
.
其中 head
是列表中的第一个元素,rest
是一个列表。
因此,例如 (1,2,3,4) 表示为 (1, (2,(3,(4,[])))) 其中 []
是空列表。
然后如果我们想遍历列表,我们可以写一个递归函数或多或少像这样:
iterate(list)
head = list.head
// do stuff and return if head is the empty element
iterate(list.rest)
如果我们想迭代每 2 个元素,我们会这样做:
pair_iterate(list)
head1 = list.head
head2 = list.rest.head
// do stuff and return if head is the empty element
iterate(list.rest.rest)
我正试图在 C++ 中获得第二种行为。
在 C++ 17 中,引入了折叠,因此可以这样做:
template<typename...types>
auto sum(types...values) {
return (... + values);
}
但是假设我们想要相邻参数的乘积之和,例如 sum(1,2,3,4)
是 1*2 + 3*4
.
在这种情况下,我们需要"fold twice"让2个头执行操作并传递列表的其余部分。类似于我的伪代码。
有没有人有关于如何连续获得 2 折的建议?
编辑:
我特别想用折叠来做,即在函数声明中,而不必依赖递归模板函数。
你可以一次解压2个参数,像这样:
template <typename T1, typename T2, typename ...Ts>
auto sum_products(T1 t1, T2 t2, Ts ...ts)
{
return t1 * t2 + sum_products(ts...);
}
并提供无参数的基本情况重载:
auto sum_products() { return 0; }
然后像这样使用它:
std::cout << sum_products(1,2,3,4); // prints 14
这里是 demo。
请注意,这仅适用于偶数个参数,但您可以轻松添加单个参数重载来处理这种情况。
更简单的方法是将原型更改为成对:
template <typename ...Pairs>
auto sum_products(Pairs ...ts)
{
return (... + (ts.first * ts.second));
}
否则通用解决方案是使用 index_sequence
:
template <std::size_t... Is, typename T>
auto sum_products_impl(std::index_sequence<Is...>, const T& t)
{
return (... + (std::get<2 * Is>(t) * std::get<2 * Is + 1>(t)));
}
template <typename ...Ts>
auto sum_products(Ts ...ts)
{
static_assert(sizeof...(Ts) % 2 == 0);
return sum_products_impl(std::make_index_sequence<sizeof...(Ts) / 2>(), std::tie(ts...));
}
我已经阅读了一些类似的问题,但我没有找到我正在寻找的确切内容。
以纯数学方式,列表被递归定义为:(head, rest)
.
其中 head
是列表中的第一个元素,rest
是一个列表。
因此,例如 (1,2,3,4) 表示为 (1, (2,(3,(4,[])))) 其中 []
是空列表。
然后如果我们想遍历列表,我们可以写一个递归函数或多或少像这样:
iterate(list)
head = list.head
// do stuff and return if head is the empty element
iterate(list.rest)
如果我们想迭代每 2 个元素,我们会这样做:
pair_iterate(list)
head1 = list.head
head2 = list.rest.head
// do stuff and return if head is the empty element
iterate(list.rest.rest)
我正试图在 C++ 中获得第二种行为。
在 C++ 17 中,引入了折叠,因此可以这样做:
template<typename...types>
auto sum(types...values) {
return (... + values);
}
但是假设我们想要相邻参数的乘积之和,例如 sum(1,2,3,4)
是 1*2 + 3*4
.
在这种情况下,我们需要"fold twice"让2个头执行操作并传递列表的其余部分。类似于我的伪代码。
有没有人有关于如何连续获得 2 折的建议?
编辑: 我特别想用折叠来做,即在函数声明中,而不必依赖递归模板函数。
你可以一次解压2个参数,像这样:
template <typename T1, typename T2, typename ...Ts>
auto sum_products(T1 t1, T2 t2, Ts ...ts)
{
return t1 * t2 + sum_products(ts...);
}
并提供无参数的基本情况重载:
auto sum_products() { return 0; }
然后像这样使用它:
std::cout << sum_products(1,2,3,4); // prints 14
这里是 demo。
请注意,这仅适用于偶数个参数,但您可以轻松添加单个参数重载来处理这种情况。
更简单的方法是将原型更改为成对:
template <typename ...Pairs>
auto sum_products(Pairs ...ts)
{
return (... + (ts.first * ts.second));
}
否则通用解决方案是使用 index_sequence
:
template <std::size_t... Is, typename T>
auto sum_products_impl(std::index_sequence<Is...>, const T& t)
{
return (... + (std::get<2 * Is>(t) * std::get<2 * Is + 1>(t)));
}
template <typename ...Ts>
auto sum_products(Ts ...ts)
{
static_assert(sizeof...(Ts) % 2 == 0);
return sum_products_impl(std::make_index_sequence<sizeof...(Ts) / 2>(), std::tie(ts...));
}