问题
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