格式工厂(三) Variadic Templates

版权声明:本文为博主原创文章,未经博主允许不得转载。

这次主要介绍C++11的又一个新特性 Variadic Templates (可变模板参数)

它的实现类似于initializer_list<>,它可是使类模板接受一包参数

本节主要应用递归的形式介绍 Variadic  Templates

1.简单的调用

#include <iostream>
#include "string"

using namespace std;

void printX() {}//为了响应最后一次printX()的调用,因为这次没有传递参数,如果不声明不带参数的函数会报错

template <typename T, typename... Types>
void printX(const T& firstArg, const Types&... args)
{
    cout<<firstArg<<endl;
    printX(args...);//递归调用
}

int main()
{
    printX(1,2,3);
    return 0;
}

输出结果

第一次调用printX()时传递的参数为(1,一包参数) 此时输出1 ,然后递归调用printX(args...)

第二次调用printX()时传递的参数为(2,3) 此时输出结果为2,然后递归调用printX(3)

第三次调用printX()时传递的参数为(3,) 此时输出结果为3,然后调用printX()  // 这就是声名不带参数的printX()的原因



2. Variadic Templates的特性调用

其实也不算Variadic Templates的特性调用,应该说所有的函数都具有这个特性

#include <iostream>
#include "string"

using namespace std;

void printX()
{
    cout<<"C"<<endl;
}

template <typename... Types>
void printX(const Types&... args)
{
    cout<<"B"<<endl;
}

template <typename T, typename... Types>
void printX(const T& firstArg, const Types&... args)
{
    cout<<"A"<<endl;
}

int main()
{
    printX(1);
    printX(1,2,3,4,5);
    printX();
    return 0;
}

输出结果

总结: 编译器就喜欢调用有特点的函数(较特化的函数)...



3.举几个Variadic Templates功能的例子



a.   Variadic Templates 实现类似于 printf()的 函数

#include <iostream>

using namespace std;

void printfA(const char *s)
{
    while (*s)
    {
        if (*s == ‘%‘ && *(++s) != ‘%‘)
            throw std::runtime_error("invalid format string: missing arguments");
        std::cout << *s++ << std:: endl;;
    }
}
template<typename T, typename... Args>
void printfA(const char* s, T value, Args... args)
{
    while (*s)
    {
        if (*s == ‘%‘ && *(++s) != ‘%‘)
        {
            std::cout << value << std::endl;
            printfA(++s, args...); // call even when *s == 0 to detect extra arguments
            return;
        }
        std::cout << *s++ << std::endl;
    }
    throw std::logic_error("extra arguments provided to printf");
}
//~~~~~~~~~~~~~~~

int main()
{
    int * pi = new int;
    printfA("%d%s%p%f\n",
           10,
           "abc",
           pi,
           3.1415926
           );
    return 0;
}

输出结果

第一次调用  printfA(%d%s%p%f\n, 10, args...)   输出10

第二次调用  printfA(%s%p%f\n, "abc", args...)   输出abc

第三次调用  printfA(%p%f\n, "pi", args...)      输出[地址]

第四次调用  printfA(%f\n, "3.1415926", )      输出3.1415926

...



b.Variadic Templates 递归创建,递归继承

#include <iostream>

using namespace std;

template<typename Head, typename... Tail>
class tuple<Head,Tail...>:private tuple<Tail...>
{
    typedef tuple<Tail...> inherited;
protected:
    Head m_head;
public:
    tuple() {}
    tuple(Head v,Tail... vtail):m_head(v),inherited(vtail...){}//inheriter(vtail...)调用父类的构造函数
    auto head()->decltype(m_head){return m_head;}// Head head() { return m_head;}
    inherited& tail() {return * this;}

};

int main()
{
    tuple<int, float, string> t{41, 6.3, "nico"};
    cout<< sizeof(t) <<endl;
    cout<< t.head() <<endl;
    cout<< t.tail().head()<<endl;
    cout<< t.tail().tail().head() <<endl;

    return 0;
}

输出结果

使用递归继承的方式会将这些变量的储存地址连接起来



c.sizeof...(args)的使用

#include <iostream>

using namespace std;

template <int IDX, int MAX, typename... Args>
struct PRINT_TUPLE {
    static void print (ostream& os, const tuple<Args...>& t) {
        os << get<IDX>(t) << (IDX+1==MAX ? "" : ",");
        PRINT_TUPLE<IDX+1, MAX, Args...>::print(os,t);
    }
};
// partial specialization to end the recursion
template <int MAX, typename... Args>
struct PRINT_TUPLE<MAX, MAX, Args...>   {
    static void print (std::ostream& os, const tuple<Args...>& t)  {
    }
};
// output operator for tuples
template <typename... Args>
ostream& operator<< (ostream& os,
                     const tuple<Args...>& t)
{
    os << "[";
    PRINT_TUPLE<0, sizeof...(Args), Args...>::print(os,t); //sizeof...(args) 会获取参数个数
    return os << "]";
}

int main()
{
    cout<<make_tuple(1.5,"abc",8,10)<<endl;
    return  0;
}

输出结果



d.递归复合

#include <iostream>

using namespace std;

template<typename... Values> class tup;
template<> class tup<> { };
template<typename Head, typename... Tail>
class tup<Head, Tail...>
{
    typedef tup<Tail...> composited;
protected:
    composited m_tail;
    Head m_head;
public:
    tup() { }
    tup(Head v, Tail... vtail)
    : m_tail(vtail...), m_head(v) { }
    Head head() { return m_head; }
    composited& tail() { return m_tail; }
};

int main()
{
    tup<int, float, string> t1(41, 6.3, "nico");
    cout << sizeof(t1) << endl;          //12
    cout << t1.head() << endl;                    //41
    cout << t1.tail().head() << endl;            //6.3
    cout << t1.tail().tail().head() << endl;    //nico
    return 0;
}

输出结果

以上是Variadic Templates几个简单又实用的例子

如有错误请指正

时间: 2024-12-26 03:56:46

格式工厂(三) Variadic Templates的相关文章

C++11 : variadic templates(可变参数模板)

Introduction: Before the possibilities of the new C++ language standard, C++11, the use of templates was quite limited when it came to implementing for instance function objects (functors) & tuple facilities. Implementing these sort of things using e

Django学习案例一(blog):三.模板Templates

1.优化url配置 (1)上一节url配置用的是其中一种方式"Function views",本节进行优化,用"Including another URLconf"方式. Myblog/urls.py内容 from django.conf.urls import url,include #此处添加include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.ur

variadic templates &amp; pass by const reference &amp; member operator [] in const map &amp; gcc sucks

/// bugs code with comments #include <iostream> #include <memory> #include <unordered_map> using namespace std; class A { public: A(const std::unordered_map<int, int > &ref) : ref_m(ref) {} void test1(int index) { // std::cout

格式工厂(五) tuple

版权声明:本文为博主原创文章,未经博主允许不得转载. tuple 是一个可以装载任何变量的容器,C++11的Variadic Templates给tuple的实现带来了极大方便. tuple的实现基于递归继承,例如 std::tuple<int, float, string> t (41,6.3,"nico"); 结构图如下图 递归继承的优点是,将内存分配在连续片段上,这是在内存管理上非常好的做法 下面来介绍一下tuple的使用 std::tuple<int, flo

少是指数级的多(转)

转自 http://www.oschina.net/news/30584 原文 Less is exponentially more是 Rob Pike 自己整理的他在六月22日,旧金山的 Golang 会议上的演讲稿.清晰的介绍了 Go 的前世今生,来龙去脉.为了让更多的人能够更加清楚的认识到 Go 的优雅并喜爱上 Go,特翻译成中文,以飧读者. ------翻译分隔线------ 大道至简 这是我(Rob Pike)在 2012 年六月,旧金山 Go 会议上的演讲内容. 这是一个私人演讲.我

你应当如何学习C++(以及编程)(转载)

你应当如何学习C++(以及编程)(rev#1) By 刘未鹏(pongba) C++的罗浮宫(http://blog.csdn.net/pongba) Javascript是世界上最受误解的语言,其实C++何尝不是.坊间流传的错误的C++学习方法一抓就是一大把.我自己在学习C++的过程中也走了许多弯路,浪费了不少时间. 为什么会存在这么多错误认识?原因主要有三个,一是C++语言的细节太多.二是一些著名的C++书籍总在(不管有意还是无意)暗示语言细节的重要性和有趣.三是现代C++库的开发哲学必须用

[GeekBand] 探讨C++新标准之新语法——C++ 11~14

一. 可变参数模板(Variadic Templates) 在C++11中,出现了参数数目可变的模板,这部分在之前C++高级编程的时候就有学习到. 其实,在C中就有类似的设定.最常用的printf(),就是一个采用了一个-类型的可变参数.-类型的参数代表是一个参数组. int???sumi(int???c,???...)??{????va_list???ap; ????va_start(ap,??c); ????int???i; ????int???sum???=???c; ????c???=?

c++11介绍

C++11标准是 ISO/IEC 14882:2011 - Information technology -- Programming languages -- C++ 的简称[1]  . C++11标准由国际标准化组织(ISO)和国际电工委员会(IEC)旗下的C++标准委员会(ISO/IEC JTC1/SC22/WG21)于2011年8月12日公布[2]  ,并于2011年9月出版.2012年2月28日的国际标准草案(N3376)是最接近于C++11标准的草案(仅编辑上的修正).此次标准为C+

c++11可变参数模板的使用1

1.概述 C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数.任意类型的参数.相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进.然而由于可变模版参数比较抽象,使用起来需要一定的技巧,所以它也是C++11中最难理解和掌握的特性之一. 虽然掌握可变模版参数有一定难度,但是它却是C++11中最有意思的一个特性,本文希望带领读者由浅入深的认识和掌握这一