I am trying to specialize a templated function based on the arity of the lambda that I pass to it as an argument. This is what I have come up with for a solution:
template<typename Function, bool>
struct helper;
template<typename Function>
struct helper<Function, false>
{
auto operator()(Function&& func)
{
std::cout << "Called 2 argument version.\n";
return func(1, 2);
}
};
template<typename Function>
struct helper<Function, true>
{
auto operator()(Function&& func)
{
std::cout << "Called 3 argument version.\n";
return func(1, 2, 3);
}
};
template<typename T>
struct B
{
T a;
const T someVal() const { return a; }
};
template<typename Function, typename T>
auto higherOrderFun(Function&& func, const T& a)
{
return helper<Function, std::is_invocable<Function, decltype(a.someVal()), decltype(a.someVal()), decltype(a.someVal())>::value>{}(std::forward<Function>(func));
}
int main()
{
B<int> b;
std::cout << higherOrderFun([](auto x, auto y) {return x+y; }, b) << "\n";
std::cout << higherOrderFun([](auto x, auto y, auto z) {return x + y+z; }, b) << "\n";
return 0;
}
Is there a way to achieve this in a more elegant manner? I've looked through this: Arity of a generic lambda
However, the latest solution (florestan's) turns all arguments into aribtrary_t
, so one has to cast them back inside of each lambda, which I do not find ideal. Ideally I would have liked to directly specialize the templated higherOrderFun
with SFINAE, but as it is I use a helper class in order to achieve that. Is there a more straighforward way? For instance to apply SFINAE directly to higherOrderFun
without relying on a helper
class? The whole point of this is to not have to change higherOrderFun
into higherOrderFun2
and higherOrderFun3
, but rather have the compiler deduce the correct specialization from the lambda and the given argument (const T& a
).
I should mention that I also don't care about the type of the arguments to the function - just about their count, so I would have changed decltype(a.someVal())
to auto
in my example if that was possible (maybe there's a way to circumvent explicitly defining the types?).
func
can both accept two arguments and three arguments? – Travestyarity_v
for SFINAE in msvc2017 and it required the cast inside each lambda since it apparently instantiated it witharbitrary_t
when I usedarity_v
. I could try to create a minimal example when I get back though. – Shorthornarity_v<F,2>
). But as I said - this is not specifically regarding my problem, it's just something I believe would be useful in general. My problem would have been easily solved if there wasairty<F,N>
. – Shorthorn