Let's say I want to create a lambda that executes some other lambdas in order like this:
constexpr auto some_func{[]() {
// do something
}};
constexpr auto some_other_func{[]() {
// do something else
}};
constexpr auto funcs_tuple = std::tuple(some_func, some_other_func);
constexpr auto combined_funcs = do_funcs(funcs_tuple);
combined_funcs();
I have implemented the do_funcs
function as:
template <std::size_t Idx = 0, typename Tuple>
constexpr auto do_funcs(const Tuple& tup) {
return [&]() {
if constexpr (Idx < std::tuple_size_v<Tuple>) {
const auto f = std::get<Idx>(tup);
f();
do_funcs<Idx + 1>(tup)();
}
};
}
which just executes the functions in the tuple in order. However the resulting variable combined_funcs
can't be declared constexpr because the reference to funcs_tuple
in the call to do_funcs
is not a constant expression.
I am trying the code in Compiler Explorer with clang(trunk) and get
error: constexpr variable 'combined_funcs' must be initialized by a constant expression
note: reference to 'funcs_tuple' is not a constant expression
Why is this not considered a constant expression? Is there a way that I can make it constexpr?
After some trial and error I have found that instead of capturing the tuple by reference in the returned lambda from do_funcs
but rather capturing by value the resulting lambda can indeed be declared constexpr, but I really do not want to create a copy of the tuple for each recursive call to do_funcs
.
constexpr auto do_funcs(const Tuple& tup) {
// capture by value instead of reference
// |
// v
return [=]() { ...
I would also like to make a helper function that takes a parameter pack of lambdas and dispatches it as a tuple to the do_funcs
function like this:
template <typename... Funcs>
constexpr auto make_do_funcs(Funcs&&... fs) {
const auto funcs = std::tuple(std::forward<Funcs>(fs)...);
return do_funcs(funcs);
}
The reason I am using tuples instead of another method like this:
template <typename Func, typename... Funcs>
constexpr auto do_funcs(Func&& f, Funcs&&... fs) {
return [f = std::forward<Func>(f), ... fs = std::forward<Funcs>(fs)] {
f();
if constexpr (sizeof...(fs) > 0) {
do_funcs(fs...);
}
};
}
is because "perfect capture" is a C++20 feature and requires a workaround with tuples for C++17.
For further reference I am trying to make a utility "parser" for my combination parser library which executes some other parsers to create a more complex parser when needed.
combined_funcs
be declaredconstexpr
? Do you get an error? Also, don't you meancombined_funcs();
instead ofdo_funcs();
? – cigien