C++之模板元编程
通过举例详细介绍了模板的模板参数,模板特例化,模板实例化以及编译链接等模板基础知识。
本文主要分析文章中的模板元编程例子:
首先复述一下模板元编程:
从编程范型(programming paradigm)上来说,C++ 模板是函数式编程(functional programming),它的主要特点是:函数调用不产生任何副作用(没有可变的存储),用递归形式实现循环结构的功能。C++ 模板的特例化提供了条件判断能力,而模板递归嵌套提供了循环的能力,这两点使得其具有和普通语言一样通用的能力(图灵完备性)。
从编程形式来看,模板的“<>”中的模板参数相当于函数调用的输入参数,模板中的 typedef 或 static const 或 enum 定义函数返回值(类型或数值,数值仅支持整型,如果需要可以通过编码计算浮点数),代码计算是通过类型计算进而选择类型的函数实现的(C++ 属于静态类型语言,编译器对类型的操控能力很强)
模板下的控制结构:
template<bool c, typename Then, typename Else> class IF_ { }; template<typename Then, typename Else> class IF_<true, Then, Else> { public: typedef Then reType; }; template<typename Then, typename Else> class IF_<false,Then, Else> { public: typedef Else reType; }; // 隐含要求: Condition 返回值 ret,Statement 有类型 Next template<template<typename> class Condition, typename Statement> class WHILE_ { template<typename Statement> class STOP { public: typedef Statement reType; }; public: typedef typename IF_<Condition<Statement>::ret, WHILE_<Condition, typename Statement::Next>, STOP<Statement>>::reType::reType reType; }; template<int n, int e> class sum_pow { template<int i, int e> class pow_e{ public: enum{ ret=i*pow_e<i,e-1>::ret }; }; template<int i> class pow_e<i,0>{ public: enum{ ret=1 }; }; // 计算 i^e,嵌套类使得能够定义嵌套模板元函数,private 访问控制隐藏实现细节 template<int i> class pow{ public: enum{ ret=pow_e<i,e>::ret }; }; template<typename stat> class cond { public: enum{ ret=(stat::ri<=n) }; }; template<int i, int sum> class stat { public: typedef stat<i+1, sum+pow<i>::ret> Next; enum{ ri=i, ret=sum }; }; public: enum{ ret = WHILE_<cond, stat<1,0>>::reType::ret }; }; int main() { std::cout << sum_pow<10, 2>::ret << '\n'; std::cin.get(); return 0; }
//代码解析:
sum_pow<10,2>利用模板参数相当于函数调用的输入参数。::ret是函数的返回值,用enum或者static const定义的变量。1.函数调用WHILE_条件函数;2.WHILE_条件函数调用其返回类型reType;3. WHILE_条件函数调用IF_函数;4.IF_函数需要判断cond的布尔值;5.由于WHILE_函数首先执行stat<1,0>函数;6.stat<1,0>会设置ri=1; 7.cond函数的返回值为true;8. IF_函数返回THEN类型,即在此执行WHILE_函数。整个模板的执行过程就是1+ 2*2 + 3*3* +....+10*10= 385
在讲元容器之前,我们先来看看伪变长参数模板,一个可以存储小于某个数(例子中为 4 个)的任意个数,任意类型数据的元组(tuple)的例子如下:
#include <iostream> class null_type {}; // 标签类,标记参数列表末尾 template<typename T0, typename T1, typename T2, typename T3> class type_shift_node { public: typedef T0 data_type; typedef type_shift_node<T1, T2, T3, null_type> next_type; // 参数移位了 static const int num = next_type::num + 1; // 非 null_type 模板参数个数 data_type data; // 本节点数据 next_type next; // 后续所有节点数据 type_shift_node() :data(), next() { } // 构造函数 type_shift_node(T0 const& d0, T1 const& d1, T2 const& d2, T3 const& d3) :data(d0), next(d1, d2, d3, null_type()) { } // next 参数也移位了 }; template<typename T0> // 特例,递归终止 class type_shift_node<T0, null_type, null_type, null_type> { public: typedef T0 data_type; static const int num = 1; data_type data; // 本节点数据 type_shift_node() :data(), next() { } // 构造函数 type_shift_node(T0 const& d0, null_type, null_type, null_type) : data(d0) { } }; // 元组类模板,默认参数 + 嵌套递归 template<typename T0, typename T1=null_type, typename T2=null_type, typename T3=null_type> class my_tuple { public: typedef type_shift_node<T0, T1, T2, T3> tuple_type; static const int num = tuple_type::num; tuple_type t; my_tuple(T0 const& d0=T0(),T1 const& d1=T1(),T2 const& d2=T2(),T3 const& d3=T3()) : t(d0, d1, d2, d3) { } // 构造函数,默认参数 }; // 为方便访问元组数据,定义 get<unsigned>(tuple) 函数模板 template<unsigned i, typename T0, typename T1, typename T2, typename T3> class type_shift_node_traits { public: typedef typename type_shift_node_traits<i-1,T0,T1,T2,T3>::node_type::next_type node_type; typedef typename node_type::data_type data_type; static node_type& get_node(type_shift_node<T0,T1,T2,T3>& node) { return type_shift_node_traits<i-1,T0,T1,T2,T3>::get_node(node).next; } }; template<typename T0, typename T1, typename T2, typename T3> class type_shift_node_traits<0, T0, T1, T2, T3> { public: typedef typename type_shift_node<T0,T1,T2,T3> node_type; typedef typename node_type::data_type data_type; static node_type& get_node(type_shift_node<T0,T1,T2,T3>& node) { return node; } }; template<unsigned i, typename T0, typename T1, typename T2, typename T3> typename type_shift_node_traits<i,T0,T1,T2,T3>::data_type get(my_tuple<T0,T1,T2,T3>& tup) { return type_shift_node_traits<i,T0,T1,T2,T3>::get_node(tup.t).data; } int main(){ typedef my_tuple<int, char, float> tuple3; tuple3 t3(10, 'm', 1.2f); std::cout << t3.t.data << ' ' << t3.t.next.data << ' ' << t3.t.next.next.data << '\n'; std::cout << tuple3::num << '\n'; std::cout << get<2>(t3) << '\n'; // 从 0 开始,不要出现 3,否则将出现不可理解的编译错误 std::cin.get(); return 0; } //变长参数利用的就是循环,通过将参数移位,然后设定null_type的方式实现变长参数