Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Variadic Templates






Необходимо решить следующие задачи:

· Как создать класс с 1, 2, 3, 4, 5, 6, 7, 8, 9, … инициализаторами?

· Как избежать создания объекта по частям с последующим копированием результата?

· Как создать кортеж (tuple)?

Последний вопрос является ключевым: подумайте о создании кортежей! Если можно создать и использовать обобщенные кортежи, то все остальные вопросы уйдут сами собой.

Вот пример (из «Короткого введения в Variadic templates» (см. ссылки)) реализации обобщенной, строго типизированной версии функции printf(). Наверное, лучше использовать boost:: format, но давайте посмотрим на пример:

const string pi = " pi"; const char* m = " The value of %s is about %g (unless you live in %s).\n"; printf(m, pi, 3.14159, " Indiana");

 

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

void printf(const char* s) { while (s & & *s) { // Нужно удостовериться, что нет других аргументов // %% представляет символ % внутри строки формата if (*s=='%' & & *++s! ='%') throw runtime_error(" invalid format: missing arguments"); std:: cout < < *s++; } }

 

Этот случай готов и нам нужно разобраться с функцией printf() с несколькими аргументами:

// Обратите внимание на "..." template< typename T, typename... Args> // Обратите внимание на "..." void printf(const char* s, T value, Args... args) { while (s & & *s) { // Формат указан (сам формат нам не важен) if (*s=='%' & & *++s! ='%') { // используем первый аргумент, не являющийся форматом std:: cout < < value; // " достаем" первый аргумент return printf(++s, args...); } std:: cout < < *s++; } throw std:: runtime error(" extra arguments provided to printf"); }

 

Этот код просто «достает» первый аргумент, не являющийся форматной строкой, и затем вызывает себя рекурсивно. Когда таких аргументов больше не останется, будет вызвана первая (более простая) версия метода printf (). Это довольно стандартная техника из области функционального программирования, применяемая во время компиляции. Обратите внимание, как перегруженный оператор < < заменяет использование (потенциально ошибочной) «подсказки» (“hint”) в спецификаторе формата.

Тип Args… определяет так называемую «группу параметров» (“parameter pack”). По сути, это последовательность пар тип/значение, из которых вы можете «доставать» аргументы, начиная с первого. При вызове функции printf() с одним аргументом, будет выбран первый метод (printf(const char*)). При вызове функции printf() с двумя или более аргументами, будет выбран второй метод (printf(const char*, T value, Args… args)), с первым параметром s, вторым – value, и оставшиеся параметры (если они есть) будут запакованы в группу параметров args, для последующего использования. При вызове:

printf(++s, args...);

 

Группа параметров args сдвигается на один, и следующий параметр может быть обработан в виде value. И так продолжается до тех пор, пока args не станет пустым (и будет вызвана первая версия метода printf()).

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

// Шаблонная функция с переменным числом аргументов

// (т.е. функция, способная принимать произвольное количество

// аргументов произвольного типа)

template< class... Types>






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.