I have seen e.g. a relevant question on the same issue, but I have a different problem, which I think cannot be solved in any other way.
Here is function any
that computes whether unary predicate F
is true for any of the elements in a template argument pack representation (list of types) P
:
template <template <typename...> class F, typename P>
struct any;
template <
template <typename...> class F,
template <typename...> class C, typename E, typename... En
>
struct any <F, C <E, En...> > :
public _if <F <E>{}, _true, any <F, C <En...> > > { };
template <template <typename...> class F, template <typename...> class C>
struct any <F, C <> > : public _false { };
where my _true/_false
are equivalent to std::integral_constant <bool, true/false>
, and _if <C, T, E>
is equivalent to typename std::conditional <C, T, E>::type
(details are irrelevant to the question, see below).
For instance, one may write
template <typename...> struct pack { };
template <typename T> using is_int = eq <int, T>;
any <is_int, pack <int, void, float, double> >(); // evaluates to true
any <is_int, pack <char, void, float, double> >(); // evaluates to false
where eq
is equivalent to std::is_same
.
An extension to binary predicates goes as follows:
template <template <typename...> class F, typename P, typename Q>
struct any2;
template <
template <typename...> class F,
template <typename...> class C, typename E, typename... En,
template <typename...> class D, typename H, typename... Hn
>
struct any2 <F, C <E, En...>, D <H, Hn...> > :
public _if <F <E, H>{}, _true, any2 <F, C <En...>, D <Hn...> > > { };
template <
template <typename...> class F,
template <typename...> class C, typename Q
>
struct any2 <F, C <>, Q> : public _false { };
where we may now write
typedef pack <int, void, float, double> A;
typedef pack <void, float, double, int> B;
typedef pack <void, float, double, double> C;
any2 <eq, A, B>(); // false
any2 <eq, A, C>(); // true
Here comes the question. Can we extend the approach to n
-ary predicates, operating on n
input "packs" ?
This problem is different from the previous one, in that one element of each input pack is needed at the same time for the evaluation of F <...>
.
Here is a fictional attempt:
template <template <typename...> class F, typename... P>
struct any_n;
template <
template <typename...> class F,
template <typename...> class... C, typename... E, typename... En
>
struct any_n <F, C <E, En...>...> :
public _if <F <E...>{}, _true, any_n <F, C <En...>...> > { };
template <
template <typename...> class F,
template <typename...> class C, typename... P
>
struct any_n <F, C <>, P...> : public _false { };
which of course does not compile. So, can one write things like C <E, En...>...
? What would be the types of C, E, En
then?
I suspect the answer is no.
Such syntax would be extremely convenient, as e.g. in Scheme macros. I have written a C++ template implementation of this syntax in the past supporting up to two levels, using symbol dots
or etc
for ...
. But it would be entirely different to have support from the compiler (especially if you need to compile the thing on the same day).