Is it possible to determine if the first argument of a callable object (function, lambda expression, functor, etc.) depends on a template parameter? For example: (using a hypothetical type trait)
#include <iostream>
template <typename T>
void f1(T x) {}
void f2(int x) {}
int main() {
auto f3 = [](auto x) {};
std::cout << std::boolalpha
<< is_first_arg_generic<decltype(f1)>::value << std::endl
<< is_first_arg_generic<decltype(f2)>::value << std::endl;
<< is_first_arg_generic<decltype(f3)>::value << std::endl;
}
Outputs:
true
false
true
No, I don't believe this is possible.
The function template f1 is very difficult to work with, because almost all possible uses of f1 in a type or expression must either immediately convert it to a specific type, selecting just one specialization of the template, or else immediately result in a compiler error. There's no way to just pass along the template name so it could be used in a SFINAE context, since template template parameters are only for class templates and alias templates, never function templates.
You would actually have the exact same problem with the name of an overloaded set of non-template functions.
But one thing that sort of gets closer to helping: Wrap the desired function template or overloaded functions in a generic lambda. Now it can at least be used as a template argument. And the problem is reduced to figuring out your f3.
If a given type is somehow known or assumed to be a closure type, it's simple to detect whether it's the type of a generic lambda or not: the expression &F::operator() is valid for a non-generic lambda and invalid for a generic lambda. Also, you can detect whether or not any callable type can or can't be called using a specific list of argument types, and/or whether the operator() of a given callable class can be specialized by type deduction to result in a specific list of parameter types
But that's about as far as I think we can take it. There are a practically infinite number of possible argument/parameter type lists. If you can somehow restrict the possibilities you care about checking to a finite list, you could try them all. (Or if you can select a countable set of possibilities that doesn't rely on arbitrary identifiers, you could try as many as your compiler's maximum instantiation count allows.) But that doesn't really solve the problem. If multiple argument types are valid as the first argument, it could still be a non-template function whose first parameter type can implicitly convert from multiple types. Or even if you can determine only one first parameter type is ever valid, or that only one list of function parameters is valid, you could still have a function template whose first parameter is a dependent type which only ever evaluates to one specific type based on the possible template parameters deduced via other means.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With