3

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 ?

Mathieu Van Nevel
  • 1,428
  • 1
  • 10
  • 26

1 Answers1

2

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

Jason Rice
  • 1,686
  • 1
  • 12
  • 17
  • 1
    Thanks for that awesome answer, and to make me realize that I still don't have fully read hana documentation. I'm feeling a bit guilty to let you help me so often though. – Mathieu Van Nevel Aug 08 '17 at 18:11
  • no point in feeling guilty. After you fixed the title, this is quite possibly the best `boost-hana` tagged question. – Jason Rice Aug 08 '17 at 18:46