首页 > 代码库 > 格式工厂(三) Variadic Templates

格式工厂(三) 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几个简单又实用的例子

如有错误请指正

 

格式工厂(三) Variadic Templates