At the doc page of boost::hana::always
I read that
always(x)
is a function such thatalways(x)(y...) == x
for any
y...
.
This makes me think that it shouldn't behave any differently than this lambda: [](auto const&...){ return false; }
.
However it does. For instance, the following code prints 11
, but if I change the third lambda to hana::always(false)
, then it prints 00
, revealing that always
is swallowing any argument.
#include <boost/hana/functional/always.hpp>
#include <boost/hana/functional/overload.hpp>
#include <iostream>
auto fun = boost::hana::overload(
[](int){ return true; },
[](double){ return true; },
[](auto const&...){ return false; }
);
int main() {
std::cout << fun(1) << fun(1.0) << std::endl;
}
By the way, I've just discovered boost::hana::overload_linearly
, which is not an alternative to boost::hana::overload
in this case (because as much as always
would not get all the calls, it would be the [](int){ return true; }
to be greedy), but it's good to know of it.
By the way, the amount of scenarii where this quirk can bite you is astonishing! Here's another very simplified case: the code below fails to compile for the reason perfectly explained in the accepted answer, and turning either 1
to 0
make it compile.
#include <concepts>
#include <boost/hana/functional/always.hpp>
template <typename P>
struct Foo {
template<typename E>
requires requires (P p, E e) {
#if 1
{ p(e, e) } -> std::same_as<bool>;
#else
{ p(e, e) } -> std::convertible_to<bool>;
#endif
}
auto operator()(E&&) const {
}
P p;
};
#if 1
auto const foo = Foo{boost::hana::always(true)};
#else
auto const foo = Foo{[](auto const& ...){ return true; }};
#endif
int main() {
int bar;
foo(bar);
}
I was so puzzled by the fact that I could require
that a thing I know to be a predicate would return something std::convertible_to<bool>
, but not something that is std::same_as<bool>
!
In fact, always
has different overloads (as it handles reference as return value).
so, with a simplified version:
template <typename T>
struct my_always
{
T res;
template <typename ...&& Ts>
T& operator ()(Ts&&...) /* mutable */ { return res; } // #1
template <typename ...&& Ts>
const T& operator ()(Ts&&...) const { return res; } // #2
};
then
auto fun = boost::hana::overload(
my_always<bool>{ false }, // #1 & #2
[](int){ return true; } // #3
);
std::cout << fun(1);
Possible overloads are:
bool& my_always<bool>::operator ()(int&&)
#1const bool& my_always<bool>::operator ()(int&&) const
#2bool lambda::operator() (int) const
#3All are viable here, but #1
is the best match (as fun
is not const
(and int
is not better than int&&
)).
With const
fun
, #3 would be the best match (#1 not viable, tie-breaker between #2 and #3 is template status).