C++可变参数模板(variadic template)详细介绍及代码举例

C++可变参数模板(variadic template)详细介绍及代码举例html

C++11 语言核心的改进中,最为关注的有 rvalue reference,lambda,variadic template。rvalue 规则稍微复杂,但一旦理解和记住了,应用上就没有什么困难。lambda 实际上是一个“很天然”的语言设施,除了语法稍显诡异以外,习惯了就能立刻用上,并且是能普遍用上的好东西。variadic template 这个新特性不像前二者,它自己的语法规则并不复杂,可是应用的时候确比较费脑子,好在这个技术主要是用在库的实现中,一个实现得好的库,并不会让咱们对实现的细节做任何的要求。可变参数模板(variadic template)特性自己是一个很天然的需求,它完善了 C++ 的模板设计手段。原来的模板参数可使类和函数的参数类型“任意化”,若是再加上“参数个数的任意化”,那么在参数方面的设计手段就基本上齐备了,有了variadic template 显然可让设计出来的函数或是类有更大的复用性。由于有不少处理都是与“处理对象的个数”关系不大的,好比说打屏(printf),好比说比较大小(max,min),好比函数绑定子(bind,function要对应各类可能的函数就要能“任意”参数个数和类型)。若是不能对应任意个参数,那么就总会有人没法重用已有的实现,而不得再也不重复地写一个本身须要的处理,而共通库的实现者为了尽量地让本身写的类(函数)能复用在更多的场景,也不得不重复地写不少的代码或是用诡异的技巧,宏之类的去实现有限个“任意参数”的对应。(像TR1中的 bind 等)。ios

1、C++可变参数模板(variadic template)基本语法c++

声明一个带有可变参数个数的模板的语法以下所示:程序员

template<typename Element> class tuple;web

tuple<int, string> a;  // use it like this安全

在模板参数 Element 左边出现省略号 ... ,就是表示 Element 是一个模板参数包(template type parameter pack)。parameter pack(参数包)是新引入 C++ 中的概念,好比在这个例子中,Element 表示是一连串任意的参数打成的一个包。好比第2行中,Element 就是 int, string这个参数的合集。不只“类型”的模板参数(也就是typename定义的参数)能够这样作,非类型的模板参数也能够这样作。好比下面这个例子:ide

template<typename T, unsigned PrimaryDimesion, unsigned.. Dimesions>函数

class array { /**/ };this

array<double, 3, 3> rotation_matrix; //3x3 ratiation matrixspa

如今咱们知道parameter pack了,怎么在程序中真正具体地去处理打包进来的“任意个数”的参数呢?我原来觉得,编译器会提供一些像get_param<1>

(Element) 之类的内建的“参数抽取函数”给程序员使用结果不是!!看来个人思路仍是太“过程式了”。其实 C++11 用的是 unpack 和相似函数重载似的“模板特化”来抽取参数的。这是应用 variadic tempate 最“坑爹”的部分,由于它要求对“递归”和“人肉代码展开”有必定的功力啊。仍是看例子吧:

template<typename... Elements> class tuple;

template<typename Head, typename... Tail>

class tuple<Head, Tail...> : private tuple<Tail...> {

   Head head;

public:

   /* implementation */

};

template<>

class tuple<> {

   /* zero-tuple implementation */

};

第1行声明了一个能够对应任意参数的tuple类,第2行到7行声明了这个类的一个部分特化,注意,这就是抽取参数的典型方法了。

只说明一下针对 parameter pack 相对的另外一个概念,模板参数后面带省略号 ... 就是一个解包(unpack),会把这个参数所表示的参数列表解开后去匹配新的模板,或是进行模板展开。

2、C++可变参数模板举例

 新的标准库里,有不少个库都直接依赖于 variadic template 这个语言特性,好比,tuple,bind,function。但他们比较复杂,也不够“惊艳”。C++ 老爸的 C++11 的 FQA 和 Wikipedia 的例子都是“类型安全”的printf.

C++可变参数模板实例代码1


void printf(const char *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;
                // call even when *s == 0 to detect extra arguments
                printf(s + 1, args...);
                return;
            }
        }
        std::cout << *s++;
    }
    throw std::logic_error("extra arguments provided to printf");
}


C++可变参数模板实例代码2


/*
 *       g++ myPrintf.cpp -o myPrintf -std=c++0x -Wall
 *       来源:  169it
 */
#include <iostream>
#include <cstdlib>
#include <stdexcept>
void myPrintf(const char * 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 myPrintf(const char * s, T value, Args... args)
{
    while (*s)
    {
        if (*s == '%')
        {
            if (*(s + 1) == '%')
            {
                ++s;
            }
            else
            {
                std::cout << value;
                myPrintf(s + 1, args...); // 即使 *s == 0 的时候,也调用,以便用于检测多余的参数。
                return;
            }
        }
        std::cout << *s++;
    }
    throw std::logic_error("extra arguments provided to myPrintf");
}
int main ( )
{
    // 每个百分号,输出一个参数
    myPrintf( "a%bcde%fghij%kl%mn\n", 12, "interesting", 8421, "very_interesing" );
    return EXIT_SUCCESS;
}

本文连接:C++可变参数模板(variadic template)详细介绍及代码举例

相关文章
相关标签/搜索