There are a few kinds of names in C++.
There are values. There are types. There are functions (and methods). There are members. There are type templates. There are function templates. There are variable templates.
These are not the official names in the standard.
In template cases, when the template is instantiated you get the thing the template produces. So a type template when instantiated gives a type, etc.
Members (functions and variables) can become values by becoming a pointer to a member function/value. Member variable names can become a value by pairing with an object, like foo.x
.
A function name can become a value by undergoing overload resolution. In some cases the function name is not overloaded, so the overload resolution is trivial.
Etc.
Function arguments are always values. They are never templates.
Template arguments can be types, type templates or values.
Your code is trying to pass a template as a value. You cannot do this without cheating. In your specific case, you want to pass a template function.
Function templates are very much second class citizens in C++. You cannot pass a function template to any other template, nor can you pass them as a value. What you can do with them is highly limited.
So we need to wrap up the template in something that can be passed around.
Here is one approach:
template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag{};
template<class Tag>using type_t=typename Tag::type;
auto func_template = [](auto...tags) {
return [](auto&&...args)->decltype(auto) {
return func< type_t<decltype(tags)>... >( decltype(args)(args)... );
};
};
now func_template
wraps a template function of kind template<class...Ts> R f(Args...)
for nearly arbitrary types R
, Args...
and Ts...
If we assume our argument is wrapped this way, we do this:
template <class F>
void Wrapper(int n, F&& f)
{
switch (n)
{
case 1:
f(tag<std::int8_t>)();
break;
case 2:
f(tag<std::int16_t>)();
break;
default:
break;
}
}
then at point of call we do:
Wrapper( 2, func_template );
and it works.
We can generate func_template
using macros:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
->decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define FUNC_TEMPLATE(...) \
[](auto...tags) { \
return [](auto&&...args) \
RETURNS( __VA_ARGS__< type_t<decltype(tags)>... >( decltype(args)(args)... ) ); \
}
and now we can change the call site to:
Wrapper( 2, FUNC_TEMPLATE(func) );
n
is known at compile time. Then, you could just make it a parameter, and call likeWrapper<1>(f)
. Not sure what you are trying to do here, but the example could also be achieved in better ways. – Limacine