В C ++ существует несколько видов имен.
Есть значения.Есть типы.Есть функции (и методы).Есть участники.Есть шаблоны типов.Есть шаблоны функций.Существуют переменные шаблоны.
Это не официальные имена в стандарте.
В случаях, когда шаблон создается, вы получаете то, что создает шаблон.Таким образом, шаблон типа при создании экземпляра дает тип и т. Д.
Члены (функции и переменные) могут стать значениями, став указателем на функцию / значение члена.Имена переменных-членов могут стать значениями при сопряжении с объектом, например foo.x
.
Имя функции может стать значением путем разрешения перегрузки.В некоторых случаях имя функции не перегружено, поэтому разрешение перегрузки является тривиальным.
И т. Д.
Аргументы функции всегда являются значениями.Они никогда не являются шаблонами.
Аргументы шаблона могут быть типами, шаблонами типов или значениями.
Ваш код пытается передать шаблон в качестве значения.Вы не можете сделать это без обмана.В вашем конкретном случае вы хотите передать шаблонную функцию.
Шаблоны функций - очень граждане второго сорта в C ++.Вы не можете передать шаблон функции в любой другой шаблон, а также не можете передать их в качестве значения.То, что вы можете сделать с ними, сильно ограничено.
Поэтому нам нужно обернуть шаблон во что-то, что можно передать.
Вот один из подходов:
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)... );
};
};
теперь func_template
оборачивает шаблонную функцию вида template<class...Ts> R f(Args...)
для почти произвольных типов R
, Args...
и Ts...
Если мы предположим, что наш аргумент обернут этимКстати, мы делаем это:
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;
}
}
, затем в точке вызова мы делаем:
Wrapper( 2, func_template );
и это работает.
Мы можем сгенерировать func_template
, используя макросы:
#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)... ) ); \
}
и теперь мы можем изменить сайт вызова на:
Wrapper( 2, FUNC_TEMPLATE(func) );