On the one hand, the function boost::hana::is_valid is presented as follows
Checks whether a SFINAE-friendly expression is valid.
Given a SFINAE-friendly function,
is_validreturns whether the function call is valid with the given arguments. Specifically, given a functionfand argumentsargs...,is_valid(f, args...) == whether f(args...) is validThe result is returned as a compile-time
Logical.
and an example of the usage accompanies it (from the same linked page):
struct Person { std::string name; };
auto has_name = hana::is_valid([](auto&& p) -> decltype((void)p.name) { });
Person joe{"Joe"};
static_assert(has_name(joe), "");
static_assert(!has_name(1), "");
where we see that the lambda fed to is_valid is in turn fed with the actual object that we feed to has_name.
On the other hand, the book C++ Templates - The Complete Guide presents a very similar solution (and indeed the authors cite Boost.Hana and Loius Dionne), which I omit for now the details of. This solution, however, is used in a slightly different way:
constexpr auto hasFirst = isValid([](auto x) -> decltype((void)valueT(x).first) {});
static_assert(!hasFirst(type<int>));
struct S { int first; };
static_assert(hasFirst(type<S>));
The above assumes the existence of valueT and type defined/declared below
template<typename T>
struct TypeT {
using Type = T;
};
template<typename T>
constexpr auto type = TypeT<T>{};
template<typename T>
T valueT(TypeT<T>);
Now, if I understand correctly, valueT and type correspond roughly to boost::hana::traits::declval and boost::hana::type_c, so the example from the book should map to the following
constexpr auto hasFirstH = is_valid([](auto x) -> decltype((void)traits::declval(x).first) {});
static_assert(!hasFirst(hana::type_c<int>));
struct S { int first; };
static_assert(hasFirst(hana::type_c<S>));
But what is the advantage of this?
In this answer from Louis Dionne I initially understood that it's a matter of taste, but then I thought that might be the case for that specific scenario and not in general.
While writing the question, I've searched more an more (to put relevant links in it, mainly), and I eventually did find the answer in the documentation of Boost.Hana at Boost.Hana > User Manual > Introspection > Checking expression validity > Non-static members: the use of
hana::type_cto wrap a typeTin an object (not of typeT, but of typehana::type<T>!) andhana::declvalto unwrap it is useful to write those type traits when there's no object around.