#c #templates #types #variadic-templates
#c #шаблоны #типы #переменные-шаблоны
Вопрос:
Как возможно реализовать следующую простую идею?
template <typename ...Types>
void Function()
{ /* do something that depends on the Types */ }
void Test()
{
using my_types = { int, float }; // not possible
using my_types = int, float; // alternative disallowed syntax
Function<my_types>();
Function<int,float>(); // OK, but I can't specify manually
}
Почему нет прямой поддержки для списков типов такого типа? Каков простой обходной путь?
Примечания
- это в общем контексте, где я не могу вручную указать нужные мне типы.
- Я не хочу передавать объекты этих типов в функцию. Они могут быть дорогими или просто не копируемыми.
Для пояснения варианта использования: пользователь определяет класс, подобный признаку, в котором он каким-то образом определяет список типов. Позже мне нужно обработать этот список. То, как он это определяет, все еще открыто. Итак, ищу простой способ сделать это. Нет необходимости в чрезмерно сложном шаблоне «объединить список типов во время компиляции», который можно найти где-то здесь.
Комментарии:
1. Есть списки типов, смотрите любую книгу по метапрограммированию шаблонов в C , template <class… Ts> struct list { используя type = list <Ts…>; };
Ответ №1:
Возможной альтернативой является определение своего рода оболочки типа (как std::tuple
но которая абсолютно ничего не делает с аргументами шаблона)
template <typename...>
struct type_wrapper
{ };
и объявляем Function()
получение объекта этого типа
template <typename ...Types>
void Function (type_wrapper<Types...> const amp;)
{ /* do something that depends on the Types */ }
таким образом, вы можете передать объект желаемой оболочки в Function()
и позволить шаблонному вычету работать
using my_wrapped_types = type_wrapper<int, float>;
Function(my_wrapped_types{});
Почему нет прямой поддержки для списков типов такого типа? Каков простой обходной путь?
Потому что есть std::tuple
которые охватывают большинство вариантов использования и, как вы можете видеть, тривиально написать оболочку, когда вы хотите что-то более легкое.
Я не хочу передавать объекты этих типов в функцию.
Таким образом, вы передаете объект типа type_wrapper
, но экземпляр ссылочного типа не создается.
Комментарии:
1. Ах, facepalm я уже использую это для другой цели в том же коде. На этот раз мне не удалось перевести свой мозг в режим обратной логики. Итак, вы говорите, что поскольку обходной путь / оболочка настолько проста (т. Е. «прямолинейна»), никто никогда не заботился о том, чтобы включить что-то подобное
using types = A,B,...
в стандарт!?2. @не-пользователь38741 — Да, я полагаю, это причина. Добавление этого
std::tuple
охватывает множество вариантов использования.3. @не-пользователь38741 — Что касается возможного
using types = A,B,...
синтаксиса … нет, язык не поддерживает его так просто. Я не языковой уровень, поэтому я точно не знаю, почему.4. Необходимость создания и передачи объекта, который на самом деле не нужен (кроме вывода типов), настолько нелогична. (Очевидно, это не ваша вина. Ответ в порядке) Если бы можно было вызвать
Function<type_wrapper<A,B>>()
, а затем каким-то образом получить доступ к A и B, это было бы скорее прямой логикой. Возможно, это возможно сtuple
в качестве оболочки.5. @не-пользователь38741 — О, да: это возможный вызов
Function<type_wrapper<A, B>>()
. Проблема в том, что вы не можете перехватить (в качестве параметров шаблона функции)A
иB
. Вы перехватываетеT = type_wrapper<A, B>
. Ничто не запрещает вам писать некоторые пользовательские свойства типа для извлеченияA
иB
изT
, но это громоздко. Лучше пройти черезclass
/struct
, где, используя частичную специализацию, вы можете перехватитьA
иB
более простым способом (см. Ответ Jarod42).
Ответ №2:
Возможны обходные пути, в основном использующие std::tuple
:
template <typename... Types>
void Function()
{ /* do something that depends on the Types */ }
template <typename... Types>
struct FunctionHelper<std::tuple<Types...>>
{ void operator ()() const { Function<Types...>(); } };
void Test()
{
using my_types = std::tuple<int, float>;
FunctionHelper<my_types>{}();
}
Я не хочу передавать объекты этих типов в функцию
Возможный обходной путь — использовать struct для этого, как std::type_identity (C 20, но его легко переписать)
и затем
void Test()
{
constexpr auto types = std::tuple{std::type_identity<int>{}, std::type_identity<float>{}};
std::apply([](auto... args){ Function<typename decltype(args)::type...>(); }, types);
}
Комментарии:
1. Иисус Христос, спасибо. Как я мог не видеть, что это снова tuple на помощь!? (((у вас там опечатка с
using type
vs<my_types>
)))2. Как насчет того, чтобы
Function<tuple<A,B>>()
а затем иметьstd::apply
внутри функции? Не моя исходная спецификация, но от этого можно избавитьсяFunctionHelper
, или нет?A,B
Тогда они недоступны?3.
std::apply
ожидаетstd::tuple
экземпляр. Это не может быть применено напрямую (как вы сказали, типы могут не создаваться по умолчанию).