美文网首页
28章 元编程 MP: metaprogramming

28章 元编程 MP: metaprogramming

作者: my_passion | 来源:发表于2022-06-27 10:53 被阅读0次

Note

1 MP

(1) 思想 
    
    `模板 用于 [1] 编译时计算 [2] 生成代码 (类和函数)`
            
        1) 两级编程 
        2) 模板元编程 TMP    
    
    MP = "元数据" + 程序设计: 使用 他人 元程序/元编程结果, 不是 元编程
    
(2) 目的 

    [1] `类型安全`   提高 
        
        可 `计算` 数据结构或算法 所需 `确切类型` -> `消除` 很多 `显式类型转换` 
    
    [2] `运行时性能` 提高 
            
        1] `编译期计算` 并 `选择 运行时要调用的函数` 
            -> 将 `多态行为` 解析为 `直接 函数调用` 
            
        2] 用 `紧凑内存布局` 的 data structure
    
(3) vs GP
              
    1) 区分的意义: 聚焦问题重点 
        
        —————————————————————————————————————————————————————————————————————————
               |    关注的焦点   |   本质: 是一种     |       目的 
        —————————————————————————————————————————————————————————————————————————
        [1] GP |    接口说明    |   设计 哲学       |   通用 类型 或 算法 
        —————————————————————————————————————————————————————————————————————————
        [2] MP |    计算      |   编程/实现 技术    |   类型安全 + 运行时性能 高
        —————————————————————————————————————————————————————————————————————————
    
    2)
        [1] GP 可划归为 MP 第1级: `无计算`
    
        [2] 可支持 GP

            对象分配构想 // 28.1 节 
            
                On_heap 和 Scoped 用于 Obj_holder 
                  |_ _ _ _ _|               |
                       |                    |
                       |/                   |/
                      GP                    TMP 

(4) 4 个等级

    —————————————————————————————————————————————
    [1] 无计算 
            
            仅 传递 `类型 和 值 实参` 
    —————————————————————————————————————————————       
    [2] `简单计算`: 类型 或 值 上
    
            单位(Unit)相加  // 28.5 节 
            值上简单计算 
    ———————————————————————————————————————————————————————————————
    [3] `编译时检测` 的 计算 
        
            编译时选择器 std::conditional 
    ———————————————————————————————————————————————————————————————
    [4] `编译时迭代` 的 计算 
        
            阶乘 的 3种版本( 编译时计算, 版本2 还可以 运行时计算 ) 
    ———————————————————————————————————————————————————————————————
    
(5) 2 种实现 
    
    1] constexpr 函数  -> `只接受值, 且 只生成值` -> 优选 constexpr 函数, 而不是 TMP 
        
    2] 模板          -> TMP   

(6) 过度使用 
    
    MP + 宏 
         |
         |
         |/
        隐藏 `实现细节 + 糟糕的命名`
         |
         |  解决: 系统化的技术 
         |/
        (类型)别名 + 特例化 

2 编译时计算

(1) 优选 constexpr 函数, 而非 `模板` 

(2) 尽可能 `隐藏` constexpr 函数中 `TMP 实现细节` 
    
    template<typename T>
    constexpr bool Is_pod()
    {
        return std::is_pod<T>::value;
    }                   |
                        |/
                       TMP                         

3 模板

    (1) 目标 
        
        [1] 通用性 
        [2] 生成最优代码 

    (2) vs FP ( 函数式编程 )

        模板 构成了完整的 `编译时 FP` 

28.1 类型函数: 接受 (多个)类型参数 / 生成 (多个)类型结果

(1) 接受 `类型参数` -> 返回 `类型实参` 的 `关联成员 值/类型 ::value/::type`  

(2) 广义形式: 模板类( 如 iterator_traits ) -> 关联(成员)类型 (别名)     

1 类型 别名: 提取 类型 typename ::type

模板别名    
    [1] `更像 类型` 
    [2] 隐藏 ::type 实现细节 
    
    // 条件 true, 选则 T, else F
    template<bool C, typename T, typename F>
    using Conditional = typename std::conditional<C, T, F>::type;

2 类型 谓词: 提取 值 ::value

谓词: 返回 bool 值 的 (类) 函数

    std::is_pod<T>::value           是 `POD 类型` 吗 ?      
    std::is_polymorphic<T>::value   是 `多态类型` 吗 ?    
            
封装: `模板函数 + constexpr`
    [1] 统一表示    Is_pod<T>()
    [2] 隐藏实现细节
                                    
    template<typename T> 
    constexpr bool Is_pod()
    {
        return std::is_pod<T>::value;
    }

综合 Conditional & Is_pod<T>()

    Conditional<Is_pod<T>(), On_heap<T>, Scoped<T> > x;

3 选择 函数(对象): 编译时选择 -> {} 构造 函数对象 -> () 调用 operator()

Conditional<(sizeof(int) > 4), X, Y>{}(3);

using Type = Conditional<(sizeof(int) > 4), X, Y>;
Type t;
t(3);

struct X
{
    void operator()(int x) { /**/ }
};
// Y 类似

4 萃取 traits: 提取类型 的 associated type

萃取 及其 等价特性 ( auto / decltype() ):

(1) 目的: 将 1个 类型(属性: value_type)another 类型(迭代器: T*) 关联起来
(2) 应用: 非侵入式 添加类型: not change 目的类型/Iterator

    template<typename Iterator>
    struct iterator_traits
    {
        using value_type = typename Iterator::value_type;
    };
    template<typename T>
        using Value_type = typename std::iterator_traits<T>::value_type;  
    
    // ... Difference_type
    
    template<typename Iter>
    Iter search(Iter p, Iter q, Value_type<Iter> val)
    {
        Difference_type<Iter> m = q - p; 
        // ...
    }
        |
        |   auto /  decltype() 
        |/
    template<typename Iter, typename Val>
    Iter search(Iter p, Iter q, Val val)
    {
        auto m = q - p;                          // 若 不需要 命名 q - p 的 类型 
        using difference_type = decltype(q - p); // 若 需要   命名 q - p 的 类型
        // ...
    }

28.2 控制结构

1 选择

(1) 运行时选择: 普通 if 对 类型选择 无效, 因 if 语句分支 不能声明 作 唯一语句

    if(My_cond<T>() )
        using type = Square; // error 
    else 
        using type = Cube;
    
    type x; // error

(2) 编译时选择器

    Conditional<My_cond<T>(), Square, Cube>{}(99); // Ctor + operator() 
    My_cond<T>() ? Square{}(99) : Cube{}(99);
        
    // error
    ( My_cond<T>() ? Square : Cube ){}(99); // ?: 后 2各操作数 不是表达式 -> 语法错
             |
    ( My_cond<T>() ? Square{} : Cube{} )(99); // ?: 后 2各操作数 类型不相容 -> 语法错

2 迭代 和 递归: 编译时迭代递归 实现

阶乘3版本
    version1:   TMP + constexpr 函数(模板) 
    version2:   MP: constexpr 函数 - 条件运算符 ? ::                  
    version3:   类(struct)模板
    
    比较  
        version1/3 只支持 `编译时求值`, version2 还支持 `运行时求值`
        version1/2 性能一样 -> version2 更清晰
// === version1 
template<int N>
constexpr int fac()
{
    return N*fac<N-1>();
}

template<>
constexpr int fac<1>()
{
    return 1;
}

constexpr int x1 = fac<5>();
    
// === version2
constexpr int fac(int i)
{
    return (i<2) ? 1: fac(i - 1);
}
constexpr int x2 = fac(5);

// === version3
template<int N>
struct Fac
{
    static const int value = N*Fac<N-1>::value;
};

template<>
struct Fac<1>
{
    static const int value = 1;
};

constexpr int x3 = Fac<5>::value;

28.3 编译时 列表: Tuple/元组

    1 简单输出函数

    2 元素访问

    3 make_tuple

28.4 可变参数模板

1 类型安全的 printf()

2 机制 
    
    2种 参数包
        模板参数包 typename... Args
        函数参数包 ... args
        ... 0或多个
        
    (1) use 第1个 elem 
    
    (2) (函数)参数包展开: args... -> 递归调用
        
        [1] 剥离 headElem
        [2] left 实参 捆包到 (函数)参数包 ...args

28.5 国际标准单位 例子

    1 Unit
类型函数: 对象分配构想.png image.png 28.5 - 1 Tuple 1.jpg 28.5 - 1 Tuple 2.jpg 28.5 - 1 Tuple3.jpg 28.5 - 2 Tuple 元素访问 1.jpg 28.5 - 2 Tuple 元素访问 2.jpg 28.5 - 3 make_tuple.jpg 28.6 可变参数模板: 引入.jpg 可变实参 的 4 种实现.jpg 28.6 - 1 类型安全的 printf().jpg 28.6 - 1 类型安全的 printf().jpg 28.6 -2 技术细节.jpg 28.6 - 3 转发.jpg 28.6 - 4 标准库 tuple.jpg 28.7 国际标准: 用 constexpr 和 模板, 几乎可以在 `编译时计算` 任何东西.jpg Unit 加法.jpg 建议.jpg

相关文章

  • << C++程序设计语言 >>

    28章 元编程 MP: metaprogramming https://www.jianshu.com/p/045...

  • 28章 元编程 MP: metaprogramming

    Note 1 MP 2 编译时计算 3 模板 28.1 类型函数: 接受 (多个)类型参数 / 生成 (多个)类型...

  • 一文读懂元编程

    元编程(Metaprogramming)是编写、操纵程序的程序,简而言之即为用代码生成代码。元编程是一种编程范式,...

  • GNU Make

    前言 GNU make 的编写(编程)非常类似于元编程(metaprogramming),整个MAKE 的运行分成...

  • Ruby 的魔法世界——元编程(一)

    什么是元编程(Metaprogramming) 元编程就是编写能写代码的代码。 能写代码的代码……是指代码生成器么...

  • Groovy MOP与元编程

    参考: 《Groovy 程序设计》 元编程(metaprogramming)意味着编写能够操作程序的程序,包括操作...

  • 20 元编程

    值元编程(Value Metaprogramming) 常量表达式最初只能用 enum 来声明 C++98 允许在...

  • Rust for cpp dev - 宏

    宏是一种可以生成代码的代码,这种形式被称为“元编程”(metaprogramming)。我们已经使用过 Rust ...

  • Groovy学习之-运行时元编程

    Groovy学习目录-传送门 元编程(Metaprogramming)->百度百科 Groovy语言支持两种类型的...

  • Go的反射

    介绍 反射能力是一个程序自己检查自己的结构的能力,是一种元编程(metaprogramming)的形式。 类型和接...

网友评论

      本文标题:28章 元编程 MP: metaprogramming

      本文链接:https://www.haomeiwen.com/subject/tpknvrtx.html