I'd like to execute the first lambda in a list of lambdas, which isn't sfinaed out with boost hana.
I have succeeded doing that with hana::if_ but that doesn't scale to any number of lambdas.
I think I want lazy evaluation of find_if but I don't seem to grasp the documentation of hana well enough to find the right syntax.
This is where you could tell me I am trying to solve it the wrong way or help me find a syntax that allows me to evaluate lazily.
You can find a live example with all of the code from this question on Godbolt.
Example:
Say I want to implement a generic addToContainer function
template <class T>
void addToContainerIf(T &container, const typename T::value_type &element) {
auto optional_inserted =
hana::sfinae([&element](auto &c) { return c.insert(end(c), element); });
auto optional_push_backed = hana::sfinae([&element](auto &c) {
c.push_back(element);
return end(c)--;
});
hana::if_(
hana::is_nothing(optional_inserted(container)),
[&] { optional_push_backed(container); }, [] {});
}
This is supposed to behave as follows and it does:
void testIf() {
std::vector<int> v{1, 2};
std::vector<int> expected{1, 2, 3};
addToContainerIf(v, 3);
if (v.size() != expected.size()) {
std::cout << "If implementation failed: Expected v to have "
<< expected.size() << " elements, but it has " << v.size()
<< std::endl;
} else {
std::cout << "If implementation succeeded." << std::endl;
}
Now I'd like to change addToContainerIf such that it uses a hana::tuple to find the first lambda that is hana::just:
template <class T>
void addToContainerTuple(T &container, const typename T::value_type &element) {
auto optional_inserted =
hana::sfinae([&element](auto &c) { return c.insert(end(c), element); });
auto optional_push_backed = hana::sfinae([&element](auto &c) {
c.push_back(element);
return end(c)--;
});
hana::find_if(
hana::transform(hana::make_tuple(optional_inserted, optional_push_backed),
[&](auto f) { return f(container); }),
hana::is_just);
}
However this fails with
Value of: v
Expected: equals { 1, 2, 3 }
Actual: { 1, 2, 3, 3 }
Because both insert and push_back exist on std::vector.
So, instead, I'd like hana to lazily evaluate the sfinaes.
I have tried the following, but I don't understand the documentation well enough to find the correct syntax for what I want to achieve.
This fails to compile:
template <class T>
void addToContainerTupleLazy(T &container, const typename T::value_type &element) {
auto optional_inserted =
hana::sfinae([&element](auto &c) { return c.insert(end(c), element); });
auto optional_push_backed = hana::sfinae([&element](auto &c) {
c.push_back(element);
return end(c)--;
});
hana::eval(
hana::find_if(
hana::transform(hana::make_tuple(optional_inserted, optional_push_backed),
[&](auto f) { return hana::make_lazy(f)(container); }),
hana::make_lazy(hana::is_just)
)
);
}
Please see the godbolt link for the compilation error.
I found a solution myself, by not using
hana::sfinae, but insteadhana::is_valid: