C++高阶:元编程(Metaprogramming)--入门篇

模板元编程(Template Meta programming,TMP)

就是面向模板编程,把计算过程从运行时提前到编译期,提升性能;
区别于泛型编程(利用模板实现“安全的宏”)

应用场景: 编译期 数值计算类型计算、代码循环展开

思考题
用装饰器模式给存在已久的多个类(xx_config类)添加新功能: 读取 json/yaml/xml/ini 配置文件对应部分数据到本类私有成员(不同数量和类型)。就是用一句话添加新功能,注释这句话后,新功能消失

特点

  • 模板执行完全在编译期

  • 操作的数据对象只能是常量(如enum,静态常量,基本数据类型,自定义数据类型),
    不能是运行期的变量,不能用 if else for while;

  • 其计算能力受到具体编译器实现的限制(如递归嵌套深度,C++98 要求至少 17,C++11 要求至少 1024)

技巧

  • if-else逻辑可用 type_traits(类型特征)实现在编译期做判断,计算、查询、转换、选择
  • for 逻辑可用递归、重载、继承、偏特化 实现

一、核心概念:元函数(不是一个函数,功能类似函数)

(根据模板传参分为:“类型type”元函数,“值value”元函数)
函数三要素:返回值,调用方式,参数

约定 :
对于’类型’元函数,将保存返回结果的类型别名用 ::type 命名
对于’值’元函数,将保存返回结果的静态成员用 ::value 命名

1、“值”元函数: 模板传参是‘值’

#include 

using namespace std;

// 功能:求两个数的最大公约数
// 主模板:递归调用(关键点1),class 可以换成 struct
template < unsigned M, unsigned N > // 1.元函数的参数: 模板参数
class gcd {   // 元函数(不是一个函数,元函数发生在编译期,而通常函数调用发生在运行时)
public:
  static constexpr int value = gcd< N, M%N >::value; // 2.元函数的返回值:类模板的静态成员常量
};
// 特化模板:处理边界(关键点1)
template< unsigned M >
class gcd< M, 0 > {
public:
  static_assert(M != 0);
  static constexpr int value = M;
};


int main() {
    // 3.元函数的调用 通过::访问类模板的成员
    int value=gcd<12,6>::value; // 值作为模板参数  
    cout << value << endl;      // 输出 6
}

2、“类型”元函数: 模板传参是‘类型’,普通函数做不到

#include 
using namespace std;

// 功能:返回给定类型数组的维度
// 主模板, struct 可以换成 class + public:
template< typename T >
struct dim { static constexpr size_t value = 0u;}; // 当类型不是数组类型时,返回0

// 特化1: 递归也可以放在特化中,而不一定在主模板中
template< typename U, size_t N >
struct dim< U[N] > { static constexpr size_t value = 1u + dim< U >::value; };
// 特化2
template< typename U >
struct dim< U[] > { static constexpr size_t value = 1u + dim< U >::value; };

int main() {
    using array_t = int[10][20][30]; // 类型别名
    int arrry_dim = dim<array_t>::value; // 类型作为模板参数
    cout << "维度 = " << arrry_dim << endl; // 维度 = 3
}

对上面的优化版(这种更常见)

// 标准库中有一个值叫 value 的静态成员常量元函数
template <typename T, T v> struct integral_constant { static constexpr T value = v; /*....*/ };

// 下面几个继承 integral_constant, 就有静态成员 value 了
template <typename T>
struct dim : integral_constant<std::size_t, 0u> {};

template <typename U, std::size_t N>
struct dim <U[N]> : integral_constant<std::size_t, 1u + dim<U>::value > {};

template <typename U>
struct dim <U[]>  : integral_constant<std::size_t, 1u + dim<U>::value > {};

3、“类型”元函数: 模板返回值是‘类型’,普通函数做不到

// 功能:返回移除 const 限定符的相同类型
template<typename T>
struct remove_const { 
    using type = T; // 没有const 正常返回
};

template<typename T>
struct remove_const<T const> { 
    using type = T; // 移除了const 的相同类型
};

对上面的优化版(这种更常见)

template <typename T> struct type_is { using type = T; };   // 返回传入的类型, 统一命名 type

// 下面几个继承 type_is, 就有 type 了
template <typename T> struct remove_const: type_is< T > {}; // 没有 const 正常返回
template <typename T> struct remove_const<T const> : type_is< T > {}; // 移除了 const 的相同类型
// 举一反三:下面是 移除顶层 volatile 限定符
template <typename T> struct remove_volatile: type_is< T > {}; // 没有 volatile 正常返回
template <typename T> struct remove_volatile<T volatile> : type_is< T > {}; // 移除了 volatile 的相同类型

二、模板中 if-else 逻辑

三、模板中 for 逻辑

你可能感兴趣的:(CPP,c++)