No Image

Шаблон с переменным числом аргументов c

СОДЕРЖАНИЕ
0 просмотров
10 марта 2020

Шаблон с переменным числом аргументов ( С++11 ) — это шаблон класса или функции, поддерживающий произвольное число аргументов. Этот механизм особенно удобен для разработчиков библиотек C++, поскольку его можно применить к как к шаблонам классов, так и к шаблонам функций. Таким образом, он предоставляет широкий спектр широкий спектр типобезопасных и нетривиальных функций и гибких возможностей.

В шаблонах с переменным числом аргументов многоточие используется двумя способами. слева от имени параметра оно означает пакет параметров, а справа от имени параметра оно служит для развертывания пакетов параметров в отдельные имена.

В приведенном выше примере параметр Arguments означает пакет параметров. При инстанцировании класс classname может принимать переменное число аргументов, как показано в следующих примерах:

Кроме того, определение шаблонного класса с переменным числом аргументов может устанавливать требование, что должен быть передан по меньшей мере один параметр:

Ниже представлен простейший пример синтаксиса для определения шаблонной функции с переменным числом аргументов.

Далее пакет параметров Arguments развертывается для использования, что бы показать что функция принимает переменное число аргументов.

Возможны и другие формы синтаксиса шаблонной функции с переменным количеством аргументов:

Шаблонные функции с переменным числом аргументов (как и аналогичные шаблонные классы) также могут устанавливать требование о том, что должен быть передан по меньшей мере один параметр.

В шаблонах с переменным числом аргументов используется оператор sizeof. () (он не имеет отношения к старому оператору sizeof()):

В списке-параметров-шаблона (template

) параметр typename. вводит в программу пакет параметров шаблона.

В предложении объявления параметра (func(parameter-list)) многоточие "верхнего уровня" вводит пакет параметров функции, и положение многоточия имеет большое значение.

Пример проброса значений во внутренние ф-ции:

Итак, имеется какой-то шаблонный класс, в который мы хотим передать неизвестное заранее количество аргументов, но одного и того же типа.

Простейшее решение — передача через параметризованный initializer_list .

Но мы не ищем легких путей 🙂 и хотим использовать шаблон с переменным количеством аргументов, но с единственным типом всех аргументов. И с вот таким ограничением.

Читайте также:  Почему бомба сброшенная с горизонтально летящего самолета

Как выразить такое ограничение? Неважно — в рамках С++17 или С++20 (намекаю на концепты).

1 ответ 1

Есть несколько вариантов.

(1) Если тип аргументов либо известен заранее (возможно является параметром шаблона, который нужно задавать явно), тогда берем std::is_convertible и SFINAE.

В комментариях предложили std::is_same , но он менее удобен. С ним при передаче параметров иногда требовалось бы явно приводить типы: foo (1, int(2.3), int(3ll));

Так как из-за std::is_convertible параметры могут оказаться разных (неявно приводимых к T ) типов, может иметь смысл перед использованием приводить их к T , как в примере выше.

Если не нравятся (или не нужны в вашем случае) универсальные ссылки, естественно, можно использовать константные:
void foo(const P &. params)
Или вообще передавать под значению:
void foo(P . params)
В этих случаях, forward , конечно, не нужен.

Если не нравится SFINAE, можно убрать последний шаблонный параметр и использовать что-то вроде
static_assert((std::is_convertible_v

(2) Если общий тип аргументов заранее неизвестен, и вы хотите, чтобы компилятор определял его за вас, берем std::common_type .

Обратите внимание, если компилятор не смог определить подходящий общий тип, на строке typename T = std::common_type_t

Если вдруг хочется использовать static_assert вместо SFINAE, тогда нужно убрать typename T и использовать что-то вроде
static_assert(std::experimental::is_detected_v , "Invalid argument types.");
В этом случае для удобства можно добавить внутрь функции using T = std::common_type_t

; . (И не забудьте #include .)

(3) Универсальный вариант. Самый удобный, но нужно больше шаблонного кода.

Можно либо задавать тип явно, либо оставить его определение компилятору.

Тут тоже можно использовать static_assert на std::experimental::is_detected , как в варианте (2).

Вариативный шаблон или шаблон с переменным числом аргументов в программировании — шаблон с заранее неизвестным числом аргументов, которые формируют один или несколько так называемых пакетов параметров.

Читайте также:  Зимбра почта верта вход

Вариативный шаблон позволяет использовать параметризацию типов там, где требуется оперировать произвольным количеством аргументов, каждый из которых имеет произвольный тип [1] . Он может быть очень удобен в тех ситуациях, когда сценарий поведения шаблона может быть обобщён на неизвестное количество принимаемых данных [2] .

Вариативные шаблоны поддерживаются в C++ (начиная со стандарта С++11) и D.

Содержание

С++ [ править | править код ]

Вариативный шаблон в C++ был разработан Дугласом Грегором и Яакко Ярви [3] [4] и был позже стандартизирован в C++11. До появления C++11, шаблоны (классов и функций) могли принимать только фиксированное число аргументов, которые должны были быть определены, когда шаблон был впервые объявлен.

Синтаксис вариативного шаблона:

Приведенный выше шаблон класса tuple (от англ. кортеж) может принять любое число входных параметров. Например, экземпляр вышеуказанного шаблонного класса создают с тремя аргументами:

Число аргументов может быть равно нулю, поэтому tuple<> some_instance_name; будет также работать. Если вы не хотите давать возможности создавать вариативные шаблонные объекты с нулём аргументов, можно использовать следующее объявление:

Вариативные шаблоны могут также применяться к функциям.

Оператор многоточия (…) играет две роли. Когда он стоит слева от имени параметра функции, он объявляет набор параметров. Когда оператор многоточия стоит справа от шаблона или аргумента вызова функции, он распаковывает параметры в отдельные аргументы, также как и args. в теле printf ниже.

Это рекурсивный шаблон. Обратите внимание на то что эта шаблонная вариативная версия функции printf вызывает сама себя, или (если args. пуст) вариант по умолчанию.

Нет простого механизма перебора значений вариативных шаблонов. Есть несколько способов конвертации списка аргументов в один аргумент. Обычно это реализуется с помощью перегрузки функций, или, если функция может принять только один аргумента за раз — с помощью простого маркера расширения:

этот шаблон можно использовать следующим образом:

Читайте также:  Amd radeon r530 4096 мб

и он будет преобразован во что-то вроде:

Использование функции «pass» необходимо, поскольку распаковка аргументов происходит путём разделения аргументов функции через запятую, которые не эквивалентны оператору запятая. Поэтому some_function(args). ; никогда не будет работать. Кроме того, решение выше будет работать только тогда, когда возвращаемый тип some_function не void. Кроме того, вызовы some_function будут выполняться в произвольном порядке, потому что порядок вычисления аргументов функции не определён. Чтобы избежать произвольного порядка, может быть использован список инициализации в скобках, гарантирующий соблюдение последовательности слева-направо.

Вместо вызова функции, можно создать лямбда-выражение и выполнить его «на месте».

Однако, в данном конкретном примере, лямбда-функция не обязательна. Можно использовать обычные выражения:

Другой способ заключается в использовании перегрузки функций. Это более универсальный способ, но требующий немного больше строчек кода и усилий. Одна функция принимает один аргумент некоторого типа и набор аргументов, тогда как другая (завершающая) не принимает ничего. Если обе функции имеют одинаковый перечень первоначальных параметров, вызов будет неоднозначным. Например:

Вариативные шаблоны также могут быть использованы в исключениях, списках базовых классов или в списке инициализации конструктора. Например, класс может наследовать следующее:

Оператор распаковки подставит базовые классы для класса наследника ClassName ; таким образом этот класс унаследует все классы, что ему передадут. Кроме того, конструктор должен принимать ссылку на каждый базовый класс.

Что касается шаблонов вариативных функций, параметры могут быть переадресованы. В сочетании с универсальной ссылкой (см. выше), это позволяет производить отличную пересылку:

Этот код распаковывает список аргументов в конструктор TypeToConstruct. Синтаксис std::forward(params) передаёт аргументы, как и их типы, даже с учетом rvalue характеристики, конструктору. Эта функция-фабрика автоматически присваивает выделенную память в std::shared_ptr предотвращая утечки памяти.

Кроме того, число параметров в шаблоне может быть определено следующим образом:

Выражение SomeStruct ::size выдаст 2, а выражение SomeStruct<>::size выдаст 0.

Комментировать
0 просмотров
Комментариев нет, будьте первым кто его оставит

Это интересно
No Image Компьютеры
0 комментариев
No Image Компьютеры
0 комментариев
Adblock detector