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、"值"元函数: 模板传参是'值'

cpp 复制代码
#include <iostream>

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、"类型"元函数: 模板传参是'类型',普通函数做不到

cpp 复制代码
#include <iostream>
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
}

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

cpp 复制代码
// 标准库中有一个值叫 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、"类型"元函数: 模板返回值是'类型',普通函数做不到

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

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

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

cpp 复制代码
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 逻辑

相关推荐
端平入洛1 小时前
delete又未完全delete
c++
端平入洛1 天前
auto有时不auto
c++
哇哈哈20212 天前
信号量和信号
linux·c++
多恩Stone2 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
蜡笔小马2 天前
21.Boost.Geometry disjoint、distance、envelope、equals、expand和for_each算法接口详解
c++·算法·boost
超级大福宝2 天前
N皇后问题:经典回溯算法的一些分析
数据结构·c++·算法·leetcode
weiabc2 天前
printf(“%lf“, ys) 和 cout << ys 输出的浮点数格式存在细微差异
数据结构·c++·算法
问好眼2 天前
《算法竞赛进阶指南》0x01 位运算-3.64位整数乘法
c++·算法·位运算·信息学奥赛
yyjtx2 天前
DHU上机打卡D31
开发语言·c++·算法
czxyvX2 天前
020-C++之unordered容器
数据结构·c++