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_sequences 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::transformto convertSfromhana::tuple<T...>tohana::tuple<hana::type<T>...>, and then usehana::all_ofto check whether each type satisfies thecallable_with_intconcept:demo