Templates - Template variable parameter expansion

Templates - Template variable parameter expansion

A variable parameter template

C ++ 11 enhanced templates, C ++ 11 before, class templates and function templates contain only a fixed number of template parameters, new properties are now the variable parameter in C ++ 11 allows the template to the template included in the definition 0 any template parameter. Semantic variable parameter templates and the Normal template is the same, just on a slightly different wording, need to bring back ellipsis typename or class template parameter variable declaration "...."

The role of the ellipsis is twofold:

  • Declare a parameter package, the package may contain 0 parameter to any template parameter.
  • In the right template defined parameters package can be expanded into a an independent parameter.

Second, the variable parameter template function

1. Definitions

template <class... T>
void f(T... args){
        cout << sizeof...(args) << endl;        //打印变参的个数
}
f();                                            // 0
f(1, 2);                                        // 2
f(1, 2.5, "");                                  // 3

2, template parameters bag deployment mode

1) recursive function parameter pack expanded mode

Expand packet parameters by a recursive function, a parameter required to expand a function of the packet and terminating a recursive function, a function is used to terminate the recursive termination of recursion, the following examples look.

#include <iostream>
using namespace std;

// 递归终止函数
void print(){
  cout << "empty" << endl;
}
/*
或者
template <class T>
void print(T t){
  cout << t << endl;
}
或者
template<typename T,typename T1, typename T2>
void print(T t, T1 t1){
        cout<<t<<""<<t1 <<endl;
}
或者
void print(T t, T1 t1, T2 t2){
        cout<<t<<""<<t1<<""<<t2<<endl;
}
*/

// 展开函数
template <class T, class ...Args>
void print(T head, Args... rest){
  cout << "parameter " << head << endl;
  print(rest...);
}
int main(void){
  print(1,2,3,4);
  return 0;
}

Regular the output of each parameter, until the output is empty empty. There are two functions, a recursive function, and the other is a recursive function to terminate, parameter pack Args ... calls itself recursively in the process of unfolding, each parameter call parameters once a package will be less, until all parameters are expanded so far when no parameters, then call a non-template function fun to terminate the recursive process.

Process recursive call is as follows:

print(1,2,3,4);
print(2,3,4);
print(3,4);
print(4);
print();
/*
或者
print(1,2,3,4);
print(2,3,4);
print(3,4);
print(4);
*/

You can also :: enable_if way through std :: tuple and std:

template<std::size_t I = 0, typename Tuple>
typename std::enable_if<I == std::tuple_size<Tuple>::value>::type printtp(Tuplet){
}
template<std::size_t I = 0, typename Tuple>
typename std::enable_if<I < std::tuple_size<Tuple>::value>::type printtp(Tuplet){
        std::cout << std::get<I>(t) << std::endl;
        printtp<I + 1>(t);
}
template<typename... Args>
void print(Args... args){
        printtp(std::make_tuple(args...));
}

In the above code, to select the appropriate template overloads variable print parameters std :: enable_if, the basic idea is that the variable parameters into tuple template, the print function is then selected by incrementing the index parameter when the parameter when the index is less than the total number of parameters, the parameters will be continuously taken and outputting a current index, the recursion terminates when the index parameter is equal to the total number of parameters.

2) Expand the initialization parameter pack comma expression and a list of ways

Recursive function expansion parameter package is a standard practice, it is better understood, but also has a drawback, is that there must terminate an overloaded recursive function, that function must have a termination of the same name to terminate the recursion, it will feel a little inconvenience . Is there a simpler way, directly expand the parameters bag? In fact, there may not be a way to expand the parameters of the package by recursively, this way need to use a comma expressions and initialization list.

template <class ...Args>
void expand(Args... args){
  std::initializer_list<int>{(printarg(args), 0)...};
}
或者
template<typename... Args>
void expand (Args... args){
        std::initializer_list<int>{([&]{cout << args << endl; }(), 0)...};
}

{(Printarg (args), 0) ...} will expand into ((printarg (arg1), 0), (printarg (arg2), 0), (printarg (arg3), 0), etc ...)

Third, the variable parameter template class

2, bag deployment mode parameters

1) recursive templates and specialized ways to expand the parameters package

Variable parameters generally require deployment template class is defined classes 2-3, and comprising a class declaration class specified template. Defined as follows a basic variable parameter template class, this class is the sum effect of the size of the calculated parameters in the parameter type and packet at compile time, the sum <int, double, short> :: value that can be acquired 3 and type size of 14.

  • Ordinary three-stage
//前向声明
template<typename... Args>
struct Sum;

//定义
template<typename First, typename... Rest>
struct Sum<First, Rest...>{
        enum { value = Sum<First>::value +Sum< Rest...>::value};
};

//特化终止递归
template<typename Last>
struct Sum<Last>{
        enum { value = sizeof (Last) };
};
/*
或者 最后2个参数结束
template<typename First, typename Last>
struct sum<First, Last>{
        enum{ value = sizeof(First) +sizeof(Last) };
};
或者 最后0个参数结束
template<>
struct sum<> { 
	enum{ value = 0 }; 
};
*/
  • It can also be changed to a two-stage
//定义
template<typename First, typename... Rest>
struct sum{
        enum { value = Sum<First>::value+Sum< Rest...>::value };
};

//特化
template<typename Last>
struct sum<Last>{
        enum{ value = sizeof(Last) };
};

Also can be eliminated by std :: integral_constant enumeration defines the value, use std :: integral_constant can obtain the characteristics of compile-time constants, sum the previous example can be changed to this:

// 前向声明
template<typename... Args>
struct sum;

// 基本定义
template<typename First, typename... Rest>
struct sum<First, Rest...> : std::integral_constant<int, sum<First>::value + sum<Rest...>::value>
{
};
// 递归终止
template<typename Last>
struct sum<Last> : std::integral_constant<int, sizeof(Last)>{
};
sum<int,double,short>::value;// 值为14
Published 155 original articles · won praise 15 · views 160 000 +

Guess you like

Origin blog.csdn.net/wangdamingll/article/details/105142949