How to remove metaprogramming recursion with Boost Hana

↘锁芯ラ 提交于 2019-12-10 22:08:58

问题


I'm trying to create a bitset according to the type send to the function. But let's reduce the test case a little.

Warning : I'm using auto gcc extension for this example, I don't need to use template parameter.

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

Seems like my tuple is not considered Searchable, but if I try the same hana::contains outside the lambda I got no problem.

The whole error is huge so check it there : live demo

By the way, I tried to do this with a for loop but failed. Do you know a good way of doing this kind of things in C++17/20 ?


回答1:


The error is caused by an out of bounds access caused by the use of manual recursion. Part of the purpose of functional programming is to provide constructs to eliminate the possibility of these kinds of mistakes.

Here are a few examples, but it is recommended to take a look at the manual for the concept hana::Foldable as it is really foundational in using Boost.Hana.

hana::fold_left hides the recursion for you and can reduce the amount of recursive calls via fast-tracking:

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 eliminates recursion altogether using variadic pack expansion:

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



来源:https://stackoverflow.com/questions/45563975/how-to-remove-metaprogramming-recursion-with-boost-hana

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!