I want a macros/metaprogrammic trick the code above
Here is a way to do this using templates instead of macros. The below program works for arbitrary number of Functors and Ds. See the different instantiations at the end for different combinations.
//to end recursion #1
template<template<typename>typename T > void f()
{
}
//overloaded for one function parameter #2
template<template<typename>typename Functor, typename Type>
void f(Type t)
{
std::cout<<"non-variadic version called"<<std::endl; //added for debugging
Functor<Type>(1)(t);
}
//overloaded version that does most of the work
template<template<typename>typename Functor, template<typename>typename... FunctorList,typename Type, typename... TypeList>
void f(Type t, TypeList... tList)
{
std::cout<<"variadic 2 version called"<<std::endl; //added for debugging
f<Functor>(t);
f<Functor>(tList...); //basically instantiate the first argument Functor with each element of tList
//for instantiating all the remaining
if constexpr(sizeof... (FunctorList)>0 && sizeof...(tList)>0)
{
f<FunctorList...>(tList...);
f<FunctorList...>(t);
}
int i = (FunctorList<Type>(1)(t), ... , 1);
}
int main()
{
f<Functor1, Functor2>(D1(), D2());
}
Demo
Below are given the instantiations that will be generated due to different call expressions.
Instantiations for the call expression:
1: f<Functor1, Functor2>(D1(), D2());
Functor1<D1>
Functor2<D2>
Functor3<D1>
Functor3<D3>
2: f<Functor1, Functor2, Functor3>(D1(), D2(), D3());
Functor1<D1>
Functor1<D2>
Functor1<D3>
Functor2<D1>
Functor2<D2>
Functor2<D3>
Functor3<D1>
Functor3<D2>
Functor3<D3>
3. f<Functor1, Functor2, Functor3, Functor4>(D1(), D2(), D3(), D4());
Functor1<D1>
Functor1<D2>
Functor1<D3>
Functor1<D4>
Functor2<D1>
Functor2<D2>
Functor2<D3>
Functor2<D4>
Functor3<D1>
Functor3<D2>
Functor3<D3>
Functor3<D4>
and so one for arbitrary number of Functors and Ds.
This also work for asymmetric call expressions like: f<Functor1, Functor2, Functor3>(D1(), D2(), D3(), D4());