Variadic templates

Variadic Templates

可变参数模板,函数的参数可以有任意多个,参数的类型任意

1. 实现函数递归调用

实现打印任意多个不同类型参数

#include <iostream>
using namespace std;

//无参数版本
void print() {}

//n+1 个参数版本 
template <class T, class... Types>
void print(const T& firstArg, const Types&... args) {
    cout << firstArg << endl;
    print(args...);         //n个参数版本 
}

int main() {
    print(100, 4.533, "hello world!");
    return 0;
}

输出结果为
100
4.533
hello world!

在VS中单步跟踪,我发现编译器将此函数特化为三个版本
分别为:
1. void print(int, double, char *)
2. void print(dobule, char *)
3. void print(char *)
我们自己实现的无参版本 void print()
在函数调用过程中,此函数实现了递归调用,1调用2, 2调用3,3调用我们自己实现的无参版本
然后再返回3,2,1

实现任意多个参数的max

#include <iostream>
#include <algorithm>
using namespace std;

//特化,分解到只有一个参数时返回n
template<class T>
T maximum(T n) {
    return n;
}

template<class T, class... Args>
T maximum(T n, Args... args) {
    return std::max(n, maximum(args...));
}

int main() {
    cout << maximum(1,4,8,500,67,25,7,7,5,634) << endl;     //634
    cout << maximum(1.6,78.7,346.64) << endl;               //346.64
    return 0;
} 

2. 实现类的递归继承

#include <iostream>
#include <string>

//声明
template<class... Values> class tuple;
//无参版本,空类 
template<> class tuple<> {};

template<class Head, class... Tail>
class tuple<Head, Tail...> : private tuple<Tail...> {
    typedef tuple<Tail...> inherited;
public:
    tuple() {}
    //调用父类构造函数
    tuple(Head x, Tail... vtail) :_head(x), inherited(vtail...) {}
    Head head() {
        return _head;
    }
    inherited& tail() {
        return *this;
    }
private:
    Head _head;
};

int main() {
    tuple<int, double, std::string> t(1, 35.7, "Hello World!");
    std::cout << t.head() << std::endl;                 //输出1
    std::cout << t.tail().head() << std::endl;          //35.7
    std::cout << t.tail().tail().head() << std::endl;   //Hello World!
}

一个参数的tuple继承空类tuple,两个参数的继承一个参数的,三个参数的继承两个参数的……

3. 实现类的递归合成

#include <iostream>
#include <string>

//声明
template<class... Values> class tuple;
//无参版本,空类 
template<> class tuple<> {};

template<class Head, class... Tail>
class tuple<Head, Tail...> : private tuple<Tail...> {
    typedef tuple<Tail...> composed;
public:
    tuple() {}
    //调用父类构造函数
    tuple(Head x, Tail... vtail) :_head(x), _tail(vtail...) {}
    Head head() {
        return _head;
    }
    composed& tail() {
        return _tail;
    }
private:
    Head _head;
    composed _tail;
};

int main() {
    tuple<int, double, std::string> t(1, 35.7, "Hello World!");
    std::cout << t.head() << std::endl;                 //输出1
    std::cout << t.tail().head() << std::endl;          //35.7
    std::cout << t.tail().tail().head() << std::endl;   //Hello World!
}

一个参数的tuple含有空类,两个参数的tuple含有一个参数的tupe,三个参数的含有两个参数的……

下面我们借助类模板实现一个打印tuple的函数
对于tuple<int, double, std::string> t(1, 35.7, "Hello World!")
我们希望输出的格式为[1,35.7,Hello World!]
这里采用标准库的tuple 因为里面实现了函数get

#include <iostream>
#include <tuple>
#include <string>
using namespace std;

template <int INDEX, int MAX, class... Args>
struct print_tuple {
    static void print(ostream& os, const tuple<Args...>& t) {
        os << get<INDEX>(t) << (INDEX + 1 == MAX ? "" : ",");
        print_tuple<INDEX + 1, MAX, Args...>::print(os, t);
    }
};

//偏特化,当INDEX 等于 MAX时什么都不做
template <int MAX, class... Args>
struct print_tuple<MAX, MAX, Args...> {
    static void print(ostream& os, const tuple<Args...>& t) {}
};

//重载操作符 <<
template <class... Args>
ostream& operator<< (ostream& os, const tuple<Args...>& t) {
    os << "[";
    print_tuple<0, sizeof...(Args), Args...>::print(os, t);
    os << "]";
    return os;
}

int main(){
    tuple<int, double, string> t(100, 23.23, "Hello World");
    cout << t << endl;
}

输出[100,23.23,Hello World]

我最初是想借助函数模板用这样的方式输出的

template <class... Args>
ostream& operator<< (ostream& os, const tuple<Args...>& t) {
    os << "[";
    int size = sizeof...(Args);
    for (int i = 0; i < size; ++i)
        os << get<i>(t) << (i == size - 1 ? "" : ",");
    os << "]";
    return os;
}

但是编译肯定不能通过,爆出成吨的errors,因为对于函数get<T>(t),模板参数T必须是一个常量,要在编译期就能确定

4. 小结

variadic templates为c++11的重量级特性,能解决很多问题,在库的实现中有着广泛的应用,比如模板元编程黑魔法-.-,掌握了大概,离高手级的应用还差很远很远

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值