模板元编程

作者: 梅花怒 | 来源:发表于2018-11-26 11:53 被阅读6次

什么是模板元

模板元编程是一种编译期计算的编程方法。如果你学过任意一门函数式的编程语言,那么你对模板元编程的理解一定是非常容易的。


模板元的编程约定

  • 元函数
    我们约定这样的一个struct称为一个元函数:
template <template_args>
struct func
{
    do_something;
    using type = return_type;
};

对于一个元函数func,其template_args是func的参数,type是func的返回值。当然了,元函数的参数可以为空,即func是一个普通的struct而不是一个模板类,这也是元函数。

  • 元数据
    元数据是在编译期可以进行计算的数据。一般可以认为元数据有两种,即:整数值和类型。我们约定,一般情况,不要使用整数值作为元数据。因为其一,返回值永远是一个类型,这样显得对称;其二,类型永远比值好操控得多。当然,这不是绝对的规则,不要教条,例如我之前文章中写的If函数。那么,如果你想用整数值来计算,那么你可以使用整数值的外覆类:
template <int N>
struct Int
{
    using type = Int<N>;
    static const int value = N;
};
  • 元函数类
    元函数类是对元函数的一种包裹。元函数存在的目的即是为了更加方便地传递元函数(作为其他元函数的参数)。我们规定这样的一个非模板类为元函数类:
struct func_class
{
    template <template_args>
    struct apply
    {
        do_something;
        using type = return_type;
    };
};

我们约定,元函数类中包裹的元函数叫做apply。

  • 占位符表达式
    占位符表达式是这样的一种表达式:plus3<arg<1>, Int<4>, arg<2>>。其中arg<1>和arg<2>是占位符,并不是真正的plus3所期望的接受的参数。

  • Lambda表达式
    Lambda表达式是两者之一:占位符表达式、元函数类。

  • Lambda元函数
    Lambda元函数可以接受Lambda表达式,并且把Lambda表达式转化成元函数类。像这样:Lambda<T>::type。也就是说,Lambda元函数接受占位符表达式就把它转化成元函数类,接受元函数类就返回它自身。那么Lambda元函数把占位符表达式转化成什么样的元函数类呢?很简单,就比如上述说的plus3<arg<1>, Int<4>, arg<2>>这个占位符表达式。Lambda元函数把占位符表达式转化为一个元函数类,这个元函数类中的apply函数接受两个参数T1和T2(占位符所占的plus3的参数),返回值则是plus3<T1, Int<4>, T2>::type

  • Apply元函数
    Apply元函数是这样的元函数:Apply<T1, T2>::type。其中第一个参数是一个Lambda表达式,而第二个参数是传递给这个Lambda表达式的实参。最后求值。很显然,Apply元函数的实现的第一步一定是调用Lambda元函数操作第一个参数(Lambda表达式),返回一个元函数之后,再调用元函数的apply函数。

  • 惰性求值
    显然,我们用func<args>::type来调用一个元函数,得到返回值。我们::type的时机是可以选择的,这就给了我们可以惰性求值的机会。例如,我们调用我之前写过的If函数的时候,我们可以If<Flag, func1<T>, func2<T>>::type::type而不是If<Flag, func1<T>::type, func2<T>::type>::type


如何编写模板元

记住这几个Tips:

1.对于临时变量,我们可以用类型存储。这也是为什么我们建议用Int外覆类而不是int类型值的原因之一。

2.对于循环,循环对于一门语言来说其实是不必要的,可以用循环实现的一定可以用递归实现。所以慢慢习惯递归的写法,就会很自如地编写模板元程序了。

3.对于数据结构的处理,千万别妄想自己可以in-place的处理数据结构。当对数据进行修改之后,要想着构造并返回新的数据结构。

4.对于数据结构的实现,如果你熟悉Lisp的话,那么用模板元编程很容易去实现Cons,而且模板元编程还可以实现比Cons更方便的数据结构。如果你熟悉Haskell的话,其实Haskell的[a]就是Cons的语法糖。

模板元编程的具体使用方法可以参见我的文章,希望对你有启发。


Modern C++下的模板元编程

首先,可变模板参数、constexpr、if constexpr等等特性是极大地方便模板元编程的编写的,一些简单的模板元编程甚至可以用模板函数来实现,而不是模板类。当然了,对于复杂的模板元编程还是需要模板类的,因为偏特化的强大模式匹配功能是模板函数所不能替代的,除非在模板函数的参数列表中用各种标签,然而这得不偿失,很不优雅。

相关文章

  • C++11 模板元编程 - 类型操纵

    本文最开始介绍模板元编程的时候说过,模板元编程是写C++框架离不开的技术。本例将通过介绍模板元编程在dates框架...

  • 模板元编程

    什么是模板元 模板元编程是一种编译期计算的编程方法。如果你学过任意一门函数式的编程语言,那么你对模板元编程的理解一...

  • C++11 模板元编程 - 两阶段的C++语言

    前面我们介绍了C++模板元编程的基础知识。我们将模板元编程的计算对象统一到类型上,引入了元函数的概念。元函数是模板...

  • ★23.小窍门收集

    输出1-100 模板元编程 宏展开

  • 模板元编程

    在前一篇文章中介绍了使用lambda calculus构造自然数以及相关运算。在所有的图灵完备的语言中,我们都可以...

  • C++11 模板元编程 - 模板元编程的应用

    本节开始我们通过使用C++模板元编程去解决一些实际问题,来展示模板元编程针对现实问题的使用方法和设计技巧。本节中的...

  • 模板元编程1

    在C++中,如果实现一个求和的功能,可能会这么写: 或者用上递归: 但是你有没有想过,在编译期完成所有的计算,这就...

  • C++11 模板元编程 - 元编程

    从本节开始我们将模板元编程当做一门独立的函数式语言来讨论它的方方面面。 所谓元编程,就是指可以产生程序的程序。由于...

  • 7.Netty框架-Netty编程模板(编程步骤)

    一、Netty编程模板 1、Netty编程步骤: 2、Netty编程代码模板:

  • 【游戏编程精粹】目录

    一 第一章 通用编程技术 1.0 神奇的数据驱动设计1.1 面向对象的编程与设计技术1.2 使用模板元编程的快速数...

网友评论

    本文标题:模板元编程

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