如何使用 Boost Hana 删除元编程递归
How to remove metaprogramming recursion with Boost Hana
我正在尝试根据发送到函数的类型创建位集。但是让我们稍微减少测试用例。
警告:我在这个例子中使用了自动 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 中做这种事情的好方法吗?
该错误是由于使用手动递归导致的越界访问引起的。函数式编程的部分目的是提供结构来消除此类错误的可能性。
这里有几个例子,但建议看一下概念手册 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::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) | ...); }
);
};
我正在尝试根据发送到函数的类型创建位集。但是让我们稍微减少测试用例。
警告:我在这个例子中使用了自动 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 中做这种事情的好方法吗?
该错误是由于使用手动递归导致的越界访问引起的。函数式编程的部分目的是提供结构来消除此类错误的可能性。
这里有几个例子,但建议看一下概念手册 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::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) | ...); }
);
};