Assume I have the following concept:
#include <boost/hana.hpp>
#include <iostream>
namespace hana = boost::hana;
// this is only for consistency
template <typename S> concept hana_sequence = hana::Sequence<S>::value;
template <typename T> concept callable_with_int = requires(T&& t, int i) { t(i); };
I would like to define functions that work on hana_sequence
s whose elements all satisfy this concept, like e.g.:
void applyCallable(const sequence_of_callables auto& ha, int i)
{
hana::for_each(ha, [&] (auto e) {std::cerr<<"inside apply – "; e(i);});
}
int main()
{
applyCallable(hana::make_tuple(
[] (int i) {std::cerr<<"inside lambda0 "<<2*i<<"!\n";},
[] (int i) {std::cerr<<"inside lambda1 "<<i<<"!\n";}/*,
[] () {std::cerr<<"inside lambda2!\n";}*/ // this would spoil compilation, as expected
),4);
}
My problem is how to define sequence_of_callables
as a C++20 concept. After some tribulations, I came up with the following solution:
// spurious helper needed?
template <typename T> constexpr bool sequenceOfCallablesHelper = false;
template <typename... T> constexpr bool sequenceOfCallablesHelper<hana::tuple<T...>>
= hana::fold(hana::tuple_t<T...>, true, [] (bool s, auto element) {
return s && callable_with_int<typename decltype(element)::type>;});
template <typename S>
concept sequence_of_callables = ( hana_sequence<S> && sequenceOfCallablesHelper<S> );
This works as expected, but the need for the helper and its specialization is a bit ugly.
Can this be done more directly?
You can first use hana::transform
to convert S
from hana::tuple<T...>
to hana::tuple<hana::type<T>...>
, and then use hana::all_of
to check whether each type satisfies the callable_with_int
concept:
#include <boost/hana.hpp>
namespace hana = boost::hana;
// this is only for consistency
template <typename S>
concept hana_sequence = hana::Sequence<S>::value;
template <typename T>
concept callable_with_int = requires(T&& t, int i) { t(i); };
template <typename S>
concept sequence_of_callables = hana_sequence<S> &&
!!hana::all_of(
decltype(hana::transform(std::declval<S>(), hana::typeid_)){},
[]<class T>(T) { return callable_with_int<typename T::type>; });