#if 0

这一章,我们将要开始的讨论C++里面的代码生成技术。说起代码生成技术,实际上这
并不是C++的专利,作为C++子集的C语言早就已经使用了一定的代码生成技术,这就是C宏
。我想C宏大家应该非常熟悉了吧,特别是能够实现带参数的宏使得大量的库利用这种技术
来生成那些格式重复的代码,例如:微软的MFC库,跨平台的GUI库wxWidget,Boost库等等
都使用了C宏。虽然C宏在这些库里面扮演了非常重要的角色,并且仍将扮演非常重要的角
色,但是也不得不说:C宏存在着很大的问题。最基础的就是类型不安全性,这也是C++里
面出现模板语素的一个比较重要的原因。更重要的是使用C宏生成的代码仅仅只是实现了简
单的格式填空能力,并不能表达特定的算法。正是C宏的表达设计思想的不足限制了C宏的
使用范围。

说起C++模板的代码生成能力,说起来这也是一种巧合,自从90年代初期第一个C++模
板元程序(用来在编译期输出质数)被发现以来,C++迷们对模板元程序的研究就热闹起来
了,并出现了大量的关于C++模板元程序的文献。在这里我所介绍的模板元代码生成技术主
要参考了<<Modern C++ Design>>一书的GenScatterHierarchy结构,并对这种结构进行了
扩展应用,采用了前面的LOOP静态循环实现对这种结构生成的代码的操作,从而完成了一
个C++普通类的自动生成过程。所谓的C++普通类指的是一般的手工直接编写的一个类,这
种类通常包含成员变量,生成成员变量的过程可以由GenScatterHierarchy结构完成,但是
仅仅有了成员变量还不能成为一个C++类,或许成为结构体更合适;另外普通类一般还包含
了成员函数,这种成员函数的自动生成就不能通过Loki库来实现自动生成了,虽然Loki库
的GenLinearHierarchy结构可以生成函数接口,但是函数体里面的内容就不能够随心所欲
的编写了。这后面的一点正是在本文中将要进行详细讨论的。

好了,现在我们来分析前面的章节中介绍的模板元技术中已经蕴涵的代码生成技术。
实际上LOOP静态循环中已经实现了静态函数的自动生成,也就是说,编译器在编译的时候
确确实实是看到了循环所产生的所有的静态函数,而并不是运行的时候进行的函数递归调用
。下面我们来看看C++里面的多继承现象和参数化继承现象:

#endif

#ifdef CODE_NOTE
//多继承现象
class Base1{};
class Base2{};
class Base3{};
class Derived:public Base1,public Base2,public Base3{};
//模板参数化继承现象:
template <class T>Base{};
class Derived:public Base<char>,public Base<int>,public Base<float>{};
#endif//CODE_NOTE

#if 0

从上面的多继承和参数化的多继承我们可以得到什么灵感呢?如果没有,那么再考虑
一下上一章中所介绍的类型串类型,^_^这时候有没有灵感了呢?呵呵,实际上上面的代码
中的参数化多继承的基类就是一个类型遍历过程,针对每一个类型,用Base包裹住每一个
类型并作为Derived类的基类,这样就可以生成一个自己定制的类了。如果能够使这个过程
自动化,那么我们就可以认为代码被自动生成了。

现在考虑一下上面的自动化过程所需要的输入和输出分别是什么:

输入:一个cons类型串记录所有的需要的类型,一个包裹模板类
    
    输出:生成一个由所有的cons类型串中的类型作为模板参数的包裹类作为基类的类

这样如果在包裹类里面定义了一个模板参数类型的成员变量,那么生成的类中就有所
有的这些类型的变量,也就是说这些变量都成了生成的类的成员变量。
    
    好了,说到这里,我们来看看具体的实现过程是怎样的:

#endif

#ifdef CODE_NOTE
//下面是实现代码自动生成的模板元函数,主要参考了Loki的代码
//为了撤销和重做库的独立性,将该功能从Loki库中提取出来
template<class T,template<class>class Unit>
struct scatter : public Unit<T>
{
};
template<class H,class T,template<class>class Unit>
struct scatter<cons<H,T>,Unit>
        : public scatter<H,Unit>
        , public scatter<T,Unit>
{
        typedef cons<H,T> cons_type;
};
//下面的null_type参看前一章中的代码
template<template<class>class Unit>
struct scatter<null_type,Unit>
{
};
#endif//CODE_NOTE

#if 0

在给出具体的测试代码之前还需要做一件事情,那就是将上面的scatter代码放到meta.h文件中
便于代码组织,也是为了使用前面的类型null_type。关于本文所使用的meta.h文件仅仅只是在前一
章的meta.h文件的末尾追加了上面的scatter元函数,详细的内容在本文的最后给出。下面看看如何
使用上面的模板元函数scatter来自动生成代码,见CODE1:

#endif

#ifdef CODE1
//下面的是测试代码
#include <iostream>
#include "meta.h"//这里的meta.h文件内容比上一章的内容多了一些,见本文末尾
namespace xcl=pandaxcl;
template <class T> struct Unit
{
        T _value;//成员变量
};
template <class Cons>
class Class:public xcl::scatter<Cons,Unit>
{//注意这里没有任何的成员函数
};
int main()
{
        typedef xcl::cons<char,
                xcl::cons<int,
                xcl::cons<short,
                xcl::cons<long,
                xcl::cons<float,
                xcl::cons<double,
                xcl::null_type> > > > > >CONS;
        Class<CONS> var;//声明一个类型变量
        std::cout << sizeof(var) << std::endl;
        std::cout << sizeof(Class<CONS>) << std::endl;
        //下面的这些代码的成功编译标志着上面的过程确确实实产生了代码
        static_cast<Unit<char  >&>(var)._value = 1;
        static_cast<Unit<int   >&>(var)._value = 1;
        static_cast<Unit<short >&>(var)._value = 1;
        static_cast<Unit<long  >&>(var)._value = 1;
        static_cast<Unit<float >&>(var)._value = 1;
        static_cast<Unit<double>&>(var)._value = 1;
        return 0;
}
#endif//CODE1

//该程序的运行结果如下:
/*******************************************************************************
48
48
*******************************************************************************/

#if 0

从上面的程序中我们可以看出代码生成过程确实是成功完成了,但是我们还应该注意
到上面的类型串中的的类型是绝对不允许重复的,否则后面的static_cast静态转型将会出
现模棱两可的情况。这一点在Loki库已经成功的解决了,但是在我们将要讨论的撤销和重
做库中并不会出现这种情况,所以为了使得代码尽可能的简单,我们就采用最简单的方式
。因为简单的就是最好的嘛!实际上通过这种简单的类型串规定再通过外覆一个包裹层同
样可以解决类型重复的问题。

上面的生成的类中已经具备了成员变量,但这仅仅相当于实现了一种结构体,离真正
的使用还有一段距离。因为生成的类中没有成员函数,只有在有了成员函数之后才可以真
正的实用化,这就是前面的章节中介绍的cons类型和静态LOOP循环的联合使用发挥威力的
时候了。好,首先让我们来看一个具体的问题:

考虑下面的自动生成的类:

#endif
#ifdef CODE_NOTE
template<class T> struct Unit:public std::vector<T>{};
template<class Cons> class Class : public xcl::scatter<Cons,Unit>
{
public:
        //仔细考虑一下下面的这个成员函数应该如何实现?
        //该成员函数就是为了输出自动生成的类中的所有的成员变量
        //(std::vector容器成员变量)的内容。
        void print(){}
};
#endif//CODE_NOTE
#if 0

从上面自动生成的类来说,为了能够自动的根据类型将所有的成员变量的内容都
进行输出,需要写一个print成员函数,这个成员函数能够根据类型串的不同而自动的
生成相应的处理代码,关于这一点的实现参见代码CODE2:

#endif
#ifdef CODE2
#include <iostream>
#include <iterator>
#include <vector>
#include <complex>
#include <string>
#include "meta.h"//见本文末尾
namespace xcl=pandaxcl;
template<class T> struct Unit:public std::vector<T>{};
template<class Cons> class Class : public xcl::scatter<Cons,Unit>
{
        template<size_t i> struct PRINT
        {
                template<class EnvironmentType>
                static void execute(EnvironmentType&e)
                {
                        //你的代码在这里编写
                        typedef typename xcl::type<Cons,i>::result CT;
                        Unit<CT> &v = static_cast<Unit<CT>&>(e);
                        std::copy(v.begin(),v.end(),std::ostream_iterator<CT>(std::cout," "));
                        std::cout << std::endl;//用来分开不同类型的数据
                }
        };
public:
        //下面是成员函数得实现
        void print()
        {
                //通过参数传递实现了静态代码和动态代码的连接
                xcl::LOOP<PRINT,0,xcl::length<Cons>::value,1>::execute(*this);
        }
};
int main()
{
        {//这是一个自动生成类的测试
                typedef xcl::cons<char,
                        xcl::cons<int,
                        xcl::cons<float,
                        xcl::null_type> > > CONS;
                Class<CONS> var;
                //在输出之前需要初始化var变量
                static_cast<Unit<char>&>(var).push_back('A');
                static_cast<Unit<char>&>(var).push_back('B');
                static_cast<Unit<char>&>(var).push_back('C');

static_cast<Unit<int>&>(var).push_back(1);
                static_cast<Unit<int>&>(var).push_back(2);
                static_cast<Unit<int>&>(var).push_back(3);
                static_cast<Unit<int>&>(var).push_back(4);

static_cast<Unit<float>&>(var).push_back(1.1);
                static_cast<Unit<float>&>(var).push_back(2.2);
                static_cast<Unit<float>&>(var).push_back(3.3);
                static_cast<Unit<float>&>(var).push_back(4.4);
                //输出所有的成员变量的内容
                var.print();
        }
        {//这是另一个自动生成类的测试
                //修改了类型串之后不需要修改原来的print成员就可以实现所有的输出
                typedef std::complex<float> COMPLEX;
                typedef xcl::cons<char,
                        xcl::cons<COMPLEX,
                        xcl::cons<std::string,
                        xcl::null_type> > > CONS;
                Class<CONS> var;
                //在输出之前需要初始化var变量
                static_cast<Unit<char>&>(var).push_back('A');
                static_cast<Unit<char>&>(var).push_back('B');
                static_cast<Unit<char>&>(var).push_back('C');

static_cast<Unit<COMPLEX>&>(var).push_back(COMPLEX(1.1,0.1));
                static_cast<Unit<COMPLEX>&>(var).push_back(COMPLEX(2.2,0.2));
                static_cast<Unit<COMPLEX>&>(var).push_back(COMPLEX(3.3,0.3));
                static_cast<Unit<COMPLEX>&>(var).push_back(COMPLEX(4.4,0.4));

static_cast<Unit<std::string>&>(var).push_back("熊春雷");
                static_cast<Unit<std::string>&>(var).push_back("熊猫");
                static_cast<Unit<std::string>&>(var).push_back("国宝");
                static_cast<Unit<std::string>&>(var).push_back("开心");
                static_cast<Unit<std::string>&>(var).push_back("pandaxcl");
                //输出所有的成员变量的内容
                var.print();
        }
        return 0;
}
#endif//CODE2

//该程序的运行结果如下:
/*******************************************************************************
A B C 
1 2 3 4 
1.1 2.2 3.3 4.4 
A B C 
(1.1,0.1) (2.2,0.2) (3.3,0.3) (4.4,0.4) 
熊春雷 熊猫 国宝 开心 pandaxcl 
*******************************************************************************/

#if 0

从CODE2中可以看出,自动化的类Class可以根据传递的类型串自动的调整成员变量数
量,同时也会自动调整print成员函数的功能。其中后者是本文所介绍的方法,也是模板元
函数用来进行自动化编程的关键。通过print成员函数的演示,这里你是否有很多的想法呢
?呵呵:),是啊既然可以让成员函数也能够实现自动化,那么采用C++模板元编写自动化的
类将是一件可行的事情,这就看各位的发挥了。

抛砖引玉的过程基本上已经完备,接下来就是介绍一下为什么需要自动化编程的背景
了。我们在编写程序代码的时候通常是将各种不同的功能分成一个个的小模块,当一个个
的模块编写好了之后就可以以库的形式提供给客户端使用,同时还需要附带一个非常详细
的文档,用来说明如何使用这个库。通常来说,每一个库的文档都是不同的,都有各自不
同的特殊要求,这就要客户端非常熟悉所使用的库,但是通常来说,库的编写者非常熟悉
自己编写的库,而库的使用者却不熟悉这个库。在这里介绍的自动化编程就是将这种矛盾
进行缓解的一种努力方式。库的编写者将库的使用规则尽可能的编码到库中,留给库的使
用者一个通用而简单的使用界面,将那些特殊的规则留给库的编写者而不是库的使用者不
仅可以降低库的使用门槛,同时还可以大大减少使用库的过程中发生错误的可能性。

以上是我的观点,仅供参考。

本章完。

从本文还可以看出,文中实际上还留下了一个问题:自动生成代码使用的类型串中不
允许有重复类型出现,这一点实际上是一个缺陷,将会在下一章中解决。但是作为原理来
讲,本章介绍的方法在下一章里面用来解决重复类型的类型串生成代码的时候也需要采用
了这里的方法,所以非常有必要先在这里介绍这种方法。在下一章里面将会讨论如何使用
本章介绍的不含重复类型的类型串生成代码的技术用来解决含有重复类型的类型串生成代
码的问题。注意下一章中采用的方法和Loki库中采用的方法可不相同哦:)(敬请关注!)

未完。待续...

#endif
#ifdef CODE_NOTE//附录:本文使用的meta.h文件内容
#pragma once
namespace pandaxcl{
        //
        template <bool Condition,class Then,class Else>
        struct IF
        {
                typedef Then result;//将Then类型作为条件为真的返回值(返回值为类型)
        };
        template<class Then,class Else>
        struct IF<false,Then,Else>
        {
                typedef Else result;//将Else类型作为条件为假的返回值(返回值为类型)
        };
        //
        //
        加入一个外覆层来传递额外的模板参数
        template <template<size_t>class Function,size_t start,size_t finish,size_t step>
        struct LOOP
        {
                //为了能够正确的计算出实际的循环终止变量,需要对给定的终止变量
                //进行计算,以满足正确的循环语义
                enum{real_finish=(finish/step*step+start)};
                static void execute()
                {
                        LOOP_BODY<real_finish,true>::execute();
                }
                //下面的这个模板函数是为了能够实现静态代码和动态代码连接
                template <class EnvironmentType>
                static void execute(EnvironmentType&e)
                {
                        LOOP_BODY<real_finish,true>::execute(e);
                }
        private:
                //引入了一个布尔型的模板参数用来确定循环的终止条件
                template <size_t i,bool> struct LOOP_BODY
                {
                        static void execute()
                        {
                                LOOP_BODY<i-step,(i-step>start)>::execute();
                                Function<i-step>::execute();
                        }
                        //下面的这个模板函数是为了能够实现静态代码和动态代码连接
                        template <class EnvironmentType>
                        static void execute(EnvironmentType&e)
                        {
                                LOOP_BODY<i-step,(i-step>start)>::execute(e);
                                Function<i-step>::execute(e);
                        }
                };
                //循环的终止语句,停止递归以结束循环
                template <size_t i> struct LOOP_BODY<i,false>
                {
                        static void execute(){}
                        //下面的这个模板函数是为了能够实现静态代码和动态代码连接
                        template <class EnvironmentType>
                        static void execute(EnvironmentType&e){}
                };
        };
        //为了模板化必须将原来的输出函数做成一个模板结构体
        //template<size_t i> struct Function
        //{
        //      static void execute()
        //      {
        //              //你的代码在这里编写
        //      }
        //};
        //
        //
        //cons的实现,采用和STL类似的类型命名方式
        template <class FirstType,class SecondType>
        struct cons
        {
                typedef FirstType  first_type;
                typedef SecondType second_type;
        };
        struct null_type;//类型串终结符
        //下面是两个为了实现静态类型循环所需要的静态元函数
        //length元函数的实现
        template<class Type>struct length;
        template<>struct length<null_type>
        {//返回值为整数,命名为value
                enum{value=0};
        };
        template<class FirstType,class SecondType>
        struct length<cons<FirstType,SecondType> >
        {//返回值为整数,命名为value
                enum{value=1+length<SecondType>::value};
        };
        //type元函数的实现
        template<class Cons,size_t index>struct type;
        template<class FirstType,class SecondType>
        struct type<cons<FirstType,SecondType>,0>
        {//返回值为类型,命名为result
                typedef FirstType result;
        };
        template<class FirstType,class SecondType,size_t i>
        struct type<cons<FirstType,SecondType>,i>
        {//返回值为类型,命名为result
                typedef typename type<SecondType,i-1>::result result;
        };
        //
        //下面是实现代码自动生成的模板元函数,主要参考了Loki的代码
        //为了撤销和重做库的独立性,将该功能从Loki库中提取出来
        template<class T,template<class>class Unit>
        struct scatter : public Unit<T>
        {
        };
        template<class H,class T,template<class>class Unit>
        struct scatter<cons<H,T>,Unit>
                : public scatter<H,Unit>
                , public scatter<T,Unit>
        {
                typedef cons<H,T> cons_type;
        };
        //下面的null_type参看前一章中的代码
        template<template<class>class Unit>
        struct scatter<null_type,Unit>
        {
        };
        //
}//namespace pandaxcl{
#endif//CODE_NOTE//附录 
————————————————
版权声明:本文为CSDN博主「pandaxcl」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pandaxcl/article/details/667645

C++自动化(模板元)编程基础与应用(4)相关推荐

  1. 现代C++模板元编程基础

    元函数的基础介绍 C++的模板元编程是函数式编程,所以函数是一等公民.一切在编译期间执行的函数都可以称为元函数.元函数有struct和constexpr两种定义方式,前者是一直使用的,后者是C++11 ...

  2. C++模板元编程 入门简介

    最近一直在看STL和Boost,源码里边好多涉及到模板元编程技术,简单了解一下,备忘(Boost Python中的涉及模板元的部分重点关注一下). 范例引入 // 主模板 template<in ...

  3. C++ 模板元编程简介

    文章目录 1.概述 2.模板元编程的作用 3.模板元编程的组成要素 4.模板元编程的控制逻辑 4.1 if 判断 4.2 循环展开 4.3 switch/case 分支 5.特性.策略与标签 6.小结 ...

  4. 数据字典模板_C++ 模板元编程:一种屠龙之技

    概述 模板元编程可在编译时完成一些计算,说它是屠龙之技,是因为模板元编程 似乎很厉害的样子. 似乎没有地方可以用上. 假如只从实际工程出发,没有太大必要研究模板元编程.只是我还是想写写这个主题,感叹一 ...

  5. C++ 模板元编程的应用有哪些,意义是什么?

    https://www.cnblogs.com/liangliangh/p/4219879.html 为了谈应用,先谈谈使命.模板元编程的根在模板.模板的使命很简单:为自动代码生成提供方便.提高程序员 ...

  6. C++高阶必会操作--模板元编程

    泛型编程大家应该都很熟悉了,主要就是利用模板实现"安全的宏",而模板元编程区别于我们所知道的泛型编程,它是一种较为复杂的模板,属于C++的高阶操作了,它最主要的优点就在于把计算过程 ...

  7. 最好的 C++ 模板元编程干货!

    链接 | https://www.cnblogs.com/liangliangh/p/4219879.html 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能 ...

  8. 【C++ 泛型编程 进阶篇】:用std::integral_constant和std::is_*系列深入理解模板元编程

    C++ 元模版编程:用std::integral_constant和std::is_*系列深入理解模板元编程 一.模板元编程与类型特性 (Template Metaprogramming and Ty ...

  9. 模板元编程实现素数判定

    模板元编程(英语:Template metaprogramming:缩写:TMP)是一种元编程技术,不夸张的说,这项技术开启了一种新的C++编程方式.编译器使用模板产生暂时性的源码,然后再和剩下的源码 ...

  10. 编程实现算术表达式求值_用魔法打败魔法:C++模板元编程实现的scheme元循环求值器...

    本文使用 Zhihu On VSCode 创作并发布 [TOC] 前言 寒假时沉迷C++模板元编程,写了个简单的Scheme元循环求值器.可以用类似Scheme的语法写出这样的C++模板代码: _&l ...

最新文章

  1. 从.NET1.1升级到.NET2.0时出现的PInvokeStackImbalance错误
  2. 报错解决:ERROR: While executing gem ... (Gem::CommandLineError)
  3. Python入门 学习笔记
  4. java运输_JAVA-基础-方法
  5. CentOS7 修改设置静态IP和DNS
  6. 微服务RPC框架-Feign
  7. 正则表达式re.S的用法
  8. Java实现名字按拼音排序和多条件排序
  9. wav怎么转换成mp3?
  10. 计算机如何分屏操作步骤,win7怎么设置电脑分屏显示|win7分屏显示设置方法
  11. Principle for Mac(交互式UI原型设计神器)
  12. jupyter notebook 302 get打不开
  13. 宝贝数量、流量组成结构、付费和免费流量占比、提高流量价值、店铺为什么没有销量?这些你真应该看看
  14. java实现消息推送_java实现后台服务器消息推送
  15. linux系统下一页,linux下一页
  16. 同一包(package)下,两个不同类的调用操作详解
  17. 你的微信版本过低,无法正常使用此小程序,请更新微信到最新版本。
  18. csgo服务器显示指令,CSGO国服控制台怎么打开 CSGO国服指令代码大全
  19. 解析json数据巧记
  20. Python查询手机号码所在地区

热门文章

  1. word自带公式编辑_怎么在Word上编辑数学公式?教你一招
  2. linux连接库参数-l,gcc编译时,什么时候需要用-l参数指明连接库?
  3. Moviebooking电影售票系统--用例建模
  4. python使用win32*模块模拟人工操作——城通网盘下载器(零)
  5. 神经网络的原理和应用,神经网络理论及应用
  6. 蓝桥02 等差素数列 ——数论知识
  7. ftl模板引擎遍历list
  8. Oracle数据库安装及配置(一)
  9. python爬虫爬取圆通快递信息
  10. 【软件测试管理与实践-软件质量】