template<typename... T> 可变模板参数

发布时间 2023-04-26 17:17:25作者: 小小灰迪

cppreference解释地址。

模板参数包在模板参数中的顺序要求:

在主类模板中,模板参数包必须是模板参数列表中的最后一个参数。
在函数模板中,模板参数包可能出现在列表的前面,前提是以下所有参数都可以从函数参数中推导出来,或者具有默认参数:

template < typename U, typename ... Ts >     // OK: 可以推断 U 
struct valid ; 
// template<typename... Ts, typename U> // 错误:Ts... 不在最后
// struct Invalid; 
 
template < typename ... Ts , typename U, typename = void > 
void valid ( U, Ts... ) ;     // OK:可以推导出 U 
// void valid(Ts..., U); // 不能使用:Ts... 是这个位置的非推导上下文
 
valid ( 1.0 , 1, 2 , 3 ) ;      // OK:将 U 推导为 double,将 Ts 推导为 {int, int, int}

pack expansion模板参数包扩展

情况一:参数包作为参数传入另一个带有可变模板参数的模板中

被扩展为零个或多个以逗号分隔的模式实例,其中参数包的名称从包中按顺序被每个元素替换

template<class... Us>
void f(Us... pargs) {}
 
template<class... Ts>
void g(Ts... args)
{
    f(&args...); // “&args...” is a pack expansion
                 // “&args” is its pattern
}
 
g(1, 0.2, "a"); // Ts... args expand to int E1, double E2, const char* E3
                // &args... expands to &E1, &E2, &E3
                // Us... pargs expand to int* E1, double* E2, const char** E3

情况二:如果两个参数包的名称以相同的模式出现,则它们被同时扩展,并且它们必须具有相同的长度:

template<typename...>
struct Tuple {};
 
template<typename T1, typename T2>
struct Pair {};
 
template<class... Args1>
struct zip
{
    template<class... Args2>
    struct with
    {
        typedef Tuple<Pair<Args1, Args2>...> type;
        // Pair<Args1, Args2>... is the pack expansion
        // Pair<Args1, Args2> is the pattern
    };
};
 
typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
// Pair<Args1, Args2>... expands to
// Pair<short, unsigned short>, Pair<int, unsigned int> 
// T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>
 
// typedef zip<short>::with<unsigned short, unsigned>::type T2;
// error: pack expansion contains parameter packs of different lengths

情况三:如果包扩展嵌套在另一个包扩展中

则出现在最里面的包扩展中的参数包由它扩展,并且必须在封闭的包扩展中提到另一个包,但不在最里面的包中:

template < class ... Args > 
void g ( Args ... args ) 
{ 
    f ( const_cast < const Args * > ( & args ) ... ) ;  
    // const_cast<const Args*>(&args) 是模式,它同时扩展两个包 // (Args 和 args)
  
    f ( h ( args... )  + args... ) ;  // 嵌套包扩展:
    // 内包扩展是“args...”,它首先被扩展
    // outer pack expansion is h(E1, E2, E3) + args..., 它被扩展
    // second (as h(E1, E2, E3) + E1, h(E1, E2, E3) + E2, h(E1, E2, E3) + E3) 
}

在完美转发时也会用到该模板参数包:同时扩展类型和实参

template<typename... ParamT>
f(ParamT... param){
  f2(std::forward<ParamT>(param)...);
}

扩展位点

参考cppreference

  • 函数参数列表
  • 带括号的初始值设定项
  • 模板参数列表
  • Lambda 捕获
  • sizeof...运算符
  • 动态异常规范
  • ....