[C ++ 11] C ++ параметров переменных шаблона

Шаблон переменного параметра

Оригинальная ссылка: http://blog.csdn.net/xiaohu2022/article/details/69076281
общий шаблон может принимать только фиксированное количество параметров шаблона. Иногда, однако, мы можем ожидать , чтобы получить любое количество параметров шаблона шаблона, на этот раз шаблон изменяемого параметра может быть использован. Для шаблона переменного параметра, который содержит , по меньшей мере , один шаблон параметров пакета, параметры шаблона принятого пакет равен 0 или шаблон из множества параметров. Соответственно, пакет параметра функции присутствия, означает , что эта функция может принимать любое количество параметров параметров.

использование правил

Переменная класса шаблона параметр определяется следующим образом:

шаблон <имяТипа ... Типы>
 класс Кортеж 
{};

 

Это может быть любое количество экземпляров типа кортежей:

Кортеж <> t0; 
Кортеж < INT > t1; 
Кортеж < INT , строка > t2;
// Кортеж <0> ошибка; 0 не является типом

 

Если вы хотите, чтобы избежать использования 0 для конкретизации параметра шаблона появляется шаблон изменяемого параметра, вы можете быть определен шаблоном:

шаблон <имяТипа T, имяТипа ... Типы>
 класс Кортеж 
{};

 

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

Шаблон <имяТип ... Типы>
 аннулируется F (типы ... арг); 

// легитимной вызовы 
е (); 
е ( 1 ), 
F ( 3,4 , " вводный " );

 

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

Шаблон <... Ts из TypeName, имяТипа U>
 класс Invalid 
{};    // Это определение является незаконным, так как тип никогда не выведенной U 

Шаблон <... Ts из TypeName, TYPENAME U>
 аннулированию Valid (U U, Ts из арг ...);   // это законно, так как он может быть выведен типом U
 // недействительным недействительного (Ts ... арг, U U); // незаконны, никогда не может быть выведенным U 

Valid (! 1,0 , 1 , 2 , 3 ); // В это время, тип U является двойным, Ц. является {INT, INT, INT}

 

В конкретизации шаблона функции переменного параметра

Не напрямую пройти различные параметры, передаваемые переменные параметры шаблона, но может использовать рекурсивный образ использовать шаблон переменного параметра. Переменный позволяет создавать шаблон параметров списка параметров длины типобезопасного переменный. Следующее определение переменной processValues ​​шаблона функции параметра (), который позволяет типобезопасный способ принять переменное число различных типов параметров. Функция processValues ​​() обрабатывает каждое значение из списка переменных параметров, соответствующая версия handleValue выполняется для каждого параметра ().

// обработка фактической функции каждого типа 
пустот handleValue ( INT значение) {COUT << " Integer: " << значение << ENDL;}
 недействительным handleValue ( Double значение) {COUT << " Double: " << << стоимость епсИ;}
 недействительным handleValue ( Строка значение) {COUT << " Строка: " << значение << епсИ;} 

// для завершения итерации функции группового 
шаблона <Ьурепате Т> аннулированию в processValues (T Arg) 
{ 
    handleValue (Арг) ;
} // шаблон функции переменного параметр



Шаблон <Ьурепате T, ... Ц. из TypeName> аннулированию в processValues (T Arg, ... Ts из арг) 
{ 
    handleValue (Arg); 
    в processValues (арг ...); // распакованы, а затем рекурсивно 
}

 

Этот пример можно рассматривать с трех ... операторов, но есть два разных значения. В списке параметров шаблонов и список параметров функции, которая показывает параметры пакета. Как уже упоминалось ранее, пакет параметр может принимать любое количество параметров. В фактическом использовании вызова функции оператора ..., которая представляет собой расширение пакета параметров, на этот раз будет арг Unwrap, развернутого и каждый параметр, разделенные запятыми. Шаблон всегда необходимо, по меньшей мере, один параметр, арг ... при распаковке можно назвать рекурсивно processValues ​​(), так что каждый вызов будет использоваться, по меньшей мере, одного параметра шаблона. Для рекурсивного, необходимого условия завершения, только тогда, когда параметр после распаковки, прием вызова функции шаблона параметра processValues ​​(), таким образом, завершения всей рекурсии.

Если на processValues ​​() вызова следующим образом:

processsValues ( 1 , 2.5 , " тест " );

 

Которая производит рекурсивный вызов следующим образом:

processsValues ( 1 , 2.5 , " тест " ); 
    handleValue ( 1 ); 
    processsValues ( 2,5 , " тест " ); 
        handleValue ( 2.5 ); 
        processsValues ( " тест " ); 
            handleValue ( " тест " );

 

Поскольку processValues ​​handleValue () функция () функция будет автоматически вызывать правильную версию фактического вывода типа, так что этот тип списка переменных параметров является полностью безопасным. При вызове функции processValues ​​() с параметром, и нет соответствующего handleValue () функции версии, компилятор выдаст ошибку.

В передней части орудия имеет фатальный недостаток, это рекурсивный вызов параметры копируются по значению, а для некоторых типов параметров, стоимость может быть высокой . Эффективный и разумный способ, чтобы пройти мимо опорного значения, но для буквального processValues вызова () , так что будет проблема, потому что буквальные допускаются только передать константную ссылку параметров. Сравнить К счастью, мы можем рассмотреть RValue ссылки. Используйте STD :: вперед () функция может быть реализована такой обработка, когда опорные передач Rvalue к processValues () функция, значение его передается ссылка вправо, но влево , если значение передаются по ссылке на processValues () функция, которая на левой стороне, проходящей опорного значения . Вот конкретная реализация:

// для завершения итерации функции группового 
шаблона <Ьурепате Т> аннулированию в processValues (Т && Arg) 
{ 
    handleValue (STD :: Форвард <Т> (Арг)); 
} // переменные параметры шаблона функции 
шаблона <Ьурепате Т, TypeName Ц. из ...> аннулированию в processValues (Т && Arg, Ts из && ... арг) 
{ 
    handleValue (STD :: Форвард <Т> (Arg)); 
    в processValues (STD :: вперед <Ц. из> (арг) ...); / / первый вперед функция , используемая после обработки, а затем распаковывает , а затем рекурсивно 
}



 

Упрощенная функция Printf

Здесь мы реализуем упрощенную версию функции PRINTF через шаблон переменного параметра:

// 基函数
недействительным tprintf ( Const  символ * формат) 
{ 
    соиЬ << формат; 
} 

Шаблон <имяТипа T, имяТипа ... Ts>
 пустота tprintf ( Const  символ * формат, T && значение, Ts && ... арг) 
{ 
    для (*; формат! = ' \ 0 ' ; ++ формат) 
    { 
        если (* формат == ' % ' ) 
        { 
            соиЬ << значение; 
            tprintf (формат + 1, Станд :: вперед <Ts> (арг) ...); // 递归
            возврата ; 
        } 
        СоиЬ << * формат; 
    } 
} 
INT основной () 
{ 

    tprintf ( " % мирового%% \ п " , " Привет " , ' ! ' , 2017 );
    // выход: Привет, мир! 2017 
    cin.ignore ( 10 );
    вернуться  0 ; 
}

 

Основной метод его () согласуется с processValues, но из-за фиксированный первый параметр tprintf Const символа * типа.

Рекомендации

[1] Марк Грегуар. Профессиональные C ++, третье издание, 2016.
[2] параметр cppreference пакет



Первоначальный автор: Белый будет
ссылка: https: //www.jianshu.com/p/4bf4d1860588

рекомендация

отwww.cnblogs.com/xiangtingshen/p/11260110.html