【问题标题】:C++ templated packs, fold twiceC++ 模板包,折叠两次
【发布时间】:2020-06-15 01:18:59
【问题描述】:

我已经阅读了一些类似的问题,但我没有找到我正在寻找的确切内容。

在纯数学方式中,列表递归定义为:(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)

如果我们想迭代每两个元素:

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

在这种情况下,我们需要“折叠两次”以使 2 个头执行操作并传递列表的其余部分。类似于我的伪代码。

有人对如何连续获得 2 折有建议吗?

编辑: 我特别想用折叠来做,即在函数声明中,而不必依赖递归模板函数。

【问题讨论】:

  • @cigien 我认为这不是真的。起始状态 (1,2,3,4)。获取第一个关闭状态为 (1) (2,3,4),获得第二个关闭状态为 (1)(2)(3,4) 第一次递归计算 1 * 2。在列表中调用自身 (3 ,4)。弹出 2 个头,我们计算 3 * 4。然后我们将它们加在一起,我们得到 (1*2) + (3*4)。除非我查错了代码。
  • 不,没关系,只是检查一下,谢谢。

标签: c++ templates variadic-templates fold


【解决方案1】:

你可以一次解压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

请注意,这仅适用于偶数个参数,但您可以轻松添加单个参数重载来处理这种情况。

【讨论】:

  • 虽然我真的很感谢我应该澄清的答案,但如果可能的话,我想用折叠来做。您的解决方案正在使用模板递归。
  • 哦,我明白了。 fold 表达式实际上只是语法糖,但如果这是您想要的,那很好:) 无论如何我都会保留它,如果我想到更好的解决方案,请进行编辑。
  • 我确实在寻找语法糖以避免大量冗余模板污染我的代码。但确实,答案确实解决了技术问题,而不是文体问题。
【解决方案2】:

更简单的方法是将原型更改为配对:

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...));
}

【讨论】:

    猜你喜欢
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    相关资源
    最近更新 更多