Is there a way to use std::is_invocable with arbitrary function arguments types, something like: std::is_invocable<Function, auto>. The idea is to check whether Function can accept 1 argument, regardless of the type of the argument. For a use case consider two lambdas: auto lambda1 = [](auto x) {...}, auto lambda2 = [](auto x, auto y) {...}, and a higher order templated function:
// specialize for 1 argument
template<typename Function, std::enable_if_t<(std::is_invocable<Function, auto>::value && !std::is_invocable<Function, auto, auto>::value)>, bool> = true>
void higherOrderFunc(Function&& func);
// specialize for 2 arguments
template<typename Function, std::enable_if_t<std::is_invocable<Function, auto, auto>::value, bool> = true>
void higherOrderFunc(Function&& func);
The !std::is_invocable<Function, auto, auto>::value in the first case is to prevent ambiguity for overloaded functions (that is, the preferred specialization in this case would be the 2 argument one in case of ambiguity).
Note that I am aware that auto cannot be used like this in this case. I am asking whether there's a way to implement this behaviour (at least partially).
Maybe not a perfect solution... but you can try with a
passepartoutObserve that conversion operators are only declared, not defined; so this structure can be used in
decltype()and withstd::declval()(andstd::is_invocable) but can't be instantiated.Now you can write your
higherOrderFuncpassing reference topassepartouttostd::is_invocable.The trick is that if a callable waits for
auto(orauto &, orauto &&), the type is deduced aspassepartoutitself; when the callable wait a specific type (int, with or without references, in the following examples), the templateoperator T & ()(oroperator T && (), according the cases) is compatible (in a sense) with the expected type.The following is a full compiling example