【问题标题】:How to remove metaprogramming recursion with Boost Hana如何使用 Boost Hana 删除元编程递归
【发布时间】:2017-08-08 09:03:38
【问题描述】:

我正在尝试根据发送到函数的类型创建一个位集。但是让我们稍微减少一下测试用例。

警告:我在这个例子中使用了自动 gcc 扩展,我不需要使用模板参数。

namespace hana = boost::hana;

constexpr decltype(auto) rec(auto i, auto max, auto f, auto returnValue) {

  return returnValue |= f(i);
  if constexpr (i < max) //"infinite" loop if no constexpr
    return rec(i + hana::size_c<1>, max, f, returnValue);
  else
    return returnValue;
}

constexpr decltype(auto) foo(auto ct, auto ... type) {

  constexpr auto tuple = hana::make_tuple(type...);
  constexpr unsigned long returnValue = 0L;

  constexpr auto f = [tuple, ct] (auto i) {
    if (hana::contains(tuple, ct[i]))
      return 0 << decltype(i)::value;
    else
      return 0;
  };

  return rec(hana::size_c<0>, hana::size_c<3>, f, returnValue);
}

struct T1 {};
struct T2 {};
struct T3 {};

int main () {

  constexpr auto t1 = hana::type_c<T1>;
  constexpr auto t2 = hana::type_c<T2>;
  constexpr auto t3 = hana::type_c<T3>;
  constexpr auto ct = hana::make_tuple(t1, t2, t3);
  constexpr auto test = foo(ct, t1, t2);
}

似乎我的元组不被认为是可搜索的,但如果我在 lambda 之外尝试相同的 hana::contains 我没有问题。

整个错误是巨大的,所以在那里检查它:live demo

顺便说一句,我尝试使用 for 循环执行此操作,但失败了。你知道在 C++17/20 中做这种事情的好方法吗?

【问题讨论】:

  • i 超出 ct。您检查 i
  • @JasonRice 我想我现在要哭了 ^^" 我要关注错误日志的错误部分。很好的教训,谢谢:) 我应该打开一个新问题来征求意见更“现代”的代码?
  • 不,我有一个答案来循环部分问题。
  • @JasonRice 你是最棒的 ;) 谢谢

标签: c++ lambda metaprogramming boost-hana


【解决方案1】:

错误是由使用手动递归引起的越界访问引起的。函数式编程的部分目的是提供结构来消除此类错误的可能性。

这里有几个例子,但建议查看hana::Foldable 概念的手册,因为它是使用 Boost.Hana 的基础。

hana::fold_left为你隐藏了递归,可以通过快速跟踪减少递归调用的数量:

constexpr decltype(auto) foo = [](auto ct, auto ... type) {
  constexpr auto tuple = hana::make_tuple(type...);

  return hana::fold_left(hana::make_range(hana::size_c<0>, hana::size_c<3>), 0L,
    [tuple, ct](auto returnValue, auto i)
    {
      // returnValue param is not constexpr
      if (hana::contains(tuple, ct[i])) {
        return returnValue | (1 << decltype(i)::value);
      }
      else
      {
        return returnValue;
      }
    }
  );
};

hana::fold_left example

hana::unpack 使用可变参数包扩展完全消除了递归:

constexpr decltype(auto) foo = [](auto ct, auto ... type) {
  constexpr auto tuple = hana::make_tuple(type...);
  auto f = [tuple, ct](auto i)
  {
    return hana::contains(tuple, ct[i]) ? (1 << decltype(i)::value) : 0;
  };

  return hana::unpack(hana::make_range(hana::size_c<0>, hana::size_c<3>),
    [f](auto ...i) { return (f(i) | ...); }
  );
};

hana::unpack example

【讨论】:

  • 感谢您的精彩回答,让我意识到我还没有完全阅读 hana 文档。不过,让你这么频繁地帮助我,我感到有点内疚。
  • 没有必要感到内疚。修正标题后,这很可能是最好的boost-hana 标记问​​题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
  • 2014-08-17
  • 1970-01-01
  • 2020-03-20
  • 1970-01-01
相关资源
最近更新 更多