可变参数模板
C++11 > 使用方法

可变参数模板可递归使用。可变模板参数自身并不可直接用于函数或类的实现。例如，printf的C++11可变参数的替换版本实现：
void printf(const char *s) //已经没有额外的参数了，这里将要耗尽字符串s
{
    while (*s) {
        if (*s == '%') {
            if (*(s + 1) == '%') {
                ++s;
            }
            else {
                throw std::runtime_error("invalid format string: missing arguments");
            }
        }
        std::cout << *s++;
    }
}

template<typename T, typename... Args>
void printf(const char *s, T value, Args... args) //处理一对： （格式指示符，值参数）
{
    while (*s) {
        if (*s == '%') {
            if (*(s + 1) == '%') {
                ++s;
            }
            else {
                std::cout << value;

                printf(s + 1, args...); // call even when *s == 0 to detect extra arguments
                return;
            }
        }
        std::cout << *s++;
    }
    throw std::logic_error("extra arguments provided to printf");
}
这是一个递归实现的模板函数。注意这个可变参数模板实现的printf调用自身或者在args...为空时调用基本实现版本。
没有简单机制去在可变模板参数的每个单独值上迭代。几乎没有什么方式可以把参数包转为单独实参来使用。通常这靠函数重载，或者当函数可以每次捡出一个实参时用哑扩展标记（dumb expansion marker）：
#include <iostream> 

template<typename type>
type print(type param)
{
    std::cout<<param<<' ';
    return param;
}

template<typename... Args> inline void pass(Args&&...) {}

template<typename... Args> inline void expand(Args&&... args) {
    pass( print(args)... );
}

int main()
{
      expand(42, "answer", true);
}
上例中的"pass"函数是必须的，因为参数包用逗号展开后只能作为被逗号分隔开的一组函数调用实参，而不是作为逗号运算符，从而"pass"函数所能接受的调用实参个数必须是可变的，也即"pass"函数必须是可变参数函数。print(args)...;编译不能通过。 此外，上述办法要求print的返回类型不能是void；且所有对print的调用在一个非确定的顺序，因为函数实参求值的顺序是不确定的。如果要避免这种不确定的顺序，可以用大括号封闭的初始化器列表（initializer list），这保证了严格的从左到右的求值顺序。为避免void返回类型带来的麻烦，使用逗号运算符使得每个扩展元素总是返回1。例如：
#include <iostream>

template<typename T> void some_function(T value)
{
    std::cout<<value<<' ';
}

template<typename... Args> inline void expand(Args&&... args) {
    const int size = sizeof...(args) + 2;
    int arr[size]{1，(some_function(args),1 )...，2};
    std::cout<<std::endl<<sizeof(arr)/sizeof(int); //也可以用sizeof...(Args)运算符
}

int main()
{
      expand(42, "answer", true);
}
另一种方法使用重载函数的递归的终结版（"termination versions"）函数。这更为通用，但要求更多努力写更多代码。一个函数要求某种类型的实参与参数包。另一个函数没有参数。如下例：
int func() {} // termination version

template<typename Arg1, typename... Args>
int func(const Arg1& arg1, const Args&... args)
{
    process( arg1 );
    func(args...); // note: arg1 does not appear here!
}
如果args...包含至少一个实参，则将调用第二个版本的函数；如果参数包为空将调用第一个“终结”版的函数。
可变参数模板可用于异常规范（exception specification）、基类列表（base class list）、构造函数初始化列表（constructor's initialization list）。例如：
template <typename... BaseClasses> class ClassName : public BaseClasses... {
public:

    ClassName (BaseClasses&&... base_classes) : BaseClasses(base_classes)... {}
};
这个例子中的解包算子将复制所有模板参数类型为ClassName的基类型。构造函数取每个基类的引用，并初始化每个基类。
对于函数模板，可变模板参数可以转发（forward）。当与右值引用结合使用，这允许完美转发（perfect forwarding）：
template<typename TypeToConstruct> struct SharedPtrAllocator {

    template<typename ...Args> std::shared_ptr<TypeToConstruct> construct_with_shared_ptr(Args&&... params) {
        return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
    }
};
上例中，实参列表被解包给TypeToConstruct的构造函数。std::forward<Args>(params)的句法是以适当的类型转发实参。解包算子将把转发语法应用于每个参数。
模板参数包中实参的个数可以如下确定：
template<typename ...Args> struct SomeStruct {
    static const int size = sizeof...(Args);
};
例如SomeStruct<Type1, Type2>::size为2，SomeStruct<>::size为0。需要注意，sizeof...与sizeof是两个不同的运算符。
Lambda捕获例子：
template<class ...Args>
void f(Args... args) {
    auto lm = [&, args...] { return g(args...); };
    lm();
}