Typelists

Typelists是一个用来操作一大群型别的C++工具。就像list对数值提供的各种基本操作一样,typelists对型别也提供相同的操作。

有些设计模式具体制定并操作一群型别,其中也许有继承关系,显著的例子是abstract factory和visitor。如果以传统编程技术来操作一大群型别,将式全然重复的工作,如此重复将会导致隐微的代码膨胀。多数人不会想到其实它可以比现在更好。Typelists带给你一种能力,可以讲将经常性的宏工作自动化。Typelists将来自外星球的巨大威力带到C++中,让它得以支持新而有趣的一些手法。

3.1 Typelists的必要性

有时候你必须针对某些型别重复撰写相同代码,而templates无法帮上忙。假如有一个abstract factory,像这样:

class WidgetFactory
{
public:
     virtual Window* CreateWindow() = 0;
     virtual Button* CreateButton() = 0;
     virtual ScrollBar* CreateScrollBar() = 0;
};

 如果想将abstract factory概念泛化,不止生成window、bottom、scrollbar,而是任意型别。怎么办?

 如果你不试图泛化基本概念,就不太会有机会泛化这些概念的具体实体,虽然抽象基类很简单,但是你会陷入无穷无尽的派生类生成器中。

我们希望能够这样去使用一个abstract factory:

template<class T>
T* MakedWidget(WidgetFactory& factory)
{
     T* pW=factory.create<T>();
     pW=SetColor(RED);
     return pW;
}

 实际这是不可能的,如果Create不是虚函数,那么你就陷入了长长的Switch...case...之中,如果它是虚函数,那么虚函数不能是模板。

Typelists将使Abstract Factories泛化成真,并带来更多其它利益。

定义Typelists

template< class T,class U>
struct Typelist
{
    typedef T head;
    typedef T Tail;
};

  Typelists 内部没有任何数值:他的实体是空的。它们存在的理由只是为了携带型别信息。因此,对Typelists的任何处理都发生在编译期。此后我们提到一个typelist,指的是一个型别而非一个对象。虽然typlist只有两个参数,但我们可以把任意一个替换为另一个typelist,来达到无限延伸的目的。

另外我们需要一个0型别以及一个型别的Typelists,对于0型别,前面提到的NullType就可以,对于一个型别,我们可以这样定义:

typedef Typelist<int ,NullType> oneTypeOnly;

  

将Typelist生成线性化

像这样一个Typelist

typedef Typlist<int, Typelist<int, Typelist<int, Typelist<int, int> > > > Int4Type;

它太Lisp了,我们定义一系列的宏来完成它,这样我们可以忘记尖括号间的空格。

#define TYPELIST_1(T1) Typelist<T1, NullType>
#define TYPELIST_2(T1, T2) Typelist<T1, TYPELIST_1(T2) >
#define TYPELIST_3(T1, T2, T3) Typelist<T1, TYPELIST_2(T2, T3) >
#define TYPELIST_4(T1, T2, T3, T4) Typelist<T1, TYPELIST_3(T2, T3, T4) >
 //etc
#define TYPELIST_50(/* */) //

这样前面的 Int4Type 就可以这样定义  

typedef Int4Type TYPELIST_4(int, int, int, int) Int4Type;

这只是包装手法的一个开端。我们访问Int4Type的最后一个元素还比较麻烦,需要

Int4Type::Tail::Tail::Tail;

  

计算长度

我们用下面代码来计算Typelist的长度

template<class TList>struct Length;
template<> struct Length<NullType>{
    enum{value=0};
};

template<class T,class U>
struct Length<Typelist<T,U>>
{
    enum{value=1+Length<U>::value};
};

由Length<T>::value得到的是一个编译期常数,我们可以用它来定义数组大小,

std::type_info* intsRtti[Length<SignedIntegrals>::value];

这个模板代码依靠递归来完成,第一个版本是全特化,第二个版本是偏特化。

间奏曲

这里有一个问题,在Length的实现中,我们能否用迭代来取代递归?答案是否定的。因为我们在编译期编程中,可以使用到的仅仅是:template、编译期整数计算、typedef。

1、template:更明确的说是模板特化,提供编译期的if叙述。

2、整数计算:提供数值计算能力,用以从性别转为数值,但数值是不可改变的。

3、typedef:可视为用来引进“具名的型别常数”,他们也是定义之后就冻结,你不能将typedef定义的符号重新定义为另一个型别。

这些特性决定了我们无法使用迭代,所谓迭代是持有一个迭代器,并改变它,知道某些条件吻合,由于编译期我们没有“可资变化的任何东西”,所以无法实现“迭代”。所以编译期运算只能象那些纯粹函数型语言,使用大量的递归。

索引式访问

索引式访问是Typelist访问线性化,像在static世界中,索引必须是编译期常数,一个带有索引的template声明如下:

template<class TList,unsigned int index> struct TypeAt;

 实现如下:

template<class Head,Class Tail>
struct TypeAt<Typelist<Head,Tail>,0>
{
    typedef Head Result;
}

template<class Head,class Tail,unsigned int>
struct TypeAt<Typelist<Head,Tail>,i>
{
    typedef typename TypeAt<Tail,i-1>::Reslut Result;
}

  如果你试着越界访问,会编译出错。对Typelist进行索引访问,花费的时间和typelist大小有关,但这个时间全部花在编译期。

 

 查找Typelist

我们用index0f来查找Typelist中的一个型别,返回其位置,找不到就返回-1。

template <class TList, class T> struct IndexOf;
template <class T>
struct IndexOf<NullType, T>{
    enum{value = -1};
};

template <class Tail, class T>
struct IndexOf<Typelist<T, Tail>, T>{
    enum{value = 0;}
};

template <class Head, class Tail, class T>
struct IndexOf<Typelist<Head, Tail>, T>{
private:
    enum{temp = IndexOf<Tail, T>::vale};
public:
    enum{value = temp == -1 ? -1 : 1+temp};
};

最后一个特化版本是用了问号表达式来实现分支判断

  

追加元素至Typelist

修改typelist是不可能的,我们以by value方式传回一个新typelist。

template <class TList, class T> struct Append;
template <> struct Append<NullType, NullType>{
    typedef NullType Result;
};
template <class T> struct Append<NullType, T>{
    typedef TYPELIST_1(T) Result;
};
template <class Head, class Tail>
struct Append<NullType, Typelist<Head, Tail> >{
    typedef Typelist<Head, Tail> Result;
};
template <class Head, class Tail, class T>
struct Append<Typelist<Head, Tail>, T>{
    typedef Typelist<Head, typename Append<Tail,T>::Result> Result;
};

  

这个实现比较复杂,特别是最后一个偏特化版本,他递归具现Append,每次递归都将tail和待追加型别传递进去

移除typelist中的某个元素

template <class TList, class T> struct Erase;
template <class T> struct Erase<NullType, T>{
    typedef NullType Result;
};
template<class T, calss Tail>
struct Erase<Typelist<T, Tail> T>{
    typedef Tail Result;
};
template <class Head, class Tail, class T>
struct Erase<Typelist<Head, Tail>, T>{
    typedef Typelist<Head,
        typename Erase<Tail, T>::Result>
        Result;
};

  

  

时间: 2024-08-23 14:47:33

Typelists的相关文章

c++ 泛型编程 之 TypeLists

完整代码 在 http://download.csdn.net/detail/zhuyingqingfen/8457091 关于 C++ 泛型中的 TypeTraits ,参考 c++ 泛型编程 之 TypeTraits #ifndef TYPE_LISTS_H_ #define TYPE_LISTS_H_ #include <iostream> #include <string> #include "typetraits.h" /* TypeLists 内部没

C++ 模板特化以及Typelist的相关理解

近日,在学习的过程中第一次接触到了Typelist的相关内容,比如Loki库有一本Modern C++ design的一本书,大概JD搜了一波没有译本,英文版600多R,瞬间从价值上看到了这本书的价值!!这是题外话.这本书十分经典.其内容对于一个C++新手来说需要时间来理解吸收.在这里记录一下自己的理解.日后发现错误会给予更正.如有有人碰巧看到了.欢迎指正. 参考了http://blog.csdn.net/gatieme/article/details/50953564 整篇内容分了三个部分:1

jquery对标签属性操作

jquery中添加属性和删除属性: $("#2args").attr("disabled",'disabled'); $("#2args").removeAttr("disabled"); 问题背景: 选择“选项1”是,“两个参数”这个单选按钮有效. 选择“选项2”时,让“两个参数”的这个单选按钮无效. 代码: <!DOCTYPE> <html > <head> <meta chars

c++ 泛型编程 之 自动生成代码

http://download.csdn.net/detail/zhuyingqingfen/8457091 关于 C++ 泛型中的 TypeList ,参考  c++ 泛型编程 之 TypeLists #ifndef GENSCATTERHIERARCHY_H_ #define GENSCATTERHIERARCHY_H_ #include "typelists.h" #include "typetraits.h" #if defined(_MSC_VER) &a

BootStrap 学习笔记一

BootStrap学习笔记一: 学习工具:BootStrap中文文档:http://v3.bootcss.com/css/#type-lists 1.HTML5文档类型 <!DOCTYPE html> <html lang="zh-CN"> ... </html> 2.为了确保适当的绘制和触屏缩放,需要在 <head> 之中添加 viewport 元数据标签. <meta name="viewport" cont

Tinker 源码分析之DexDiff / DexPatch

本文已在我的公众号hongyangAndroid首发. 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/60874334 本文出自张鸿洋的博客 在上一篇文章中,我们介绍了Android 热修复 Tinker接入及源码浅析,里面包含了热修的一些背景知识,从tinker对dex文件的处理来看,源码大体上可以分为3部分阅读: 在应用中对patch的合并与加载,已经在上篇文章中详细介绍过了Android 热修复 Tinker接入及源码

BootStrap 学习笔记二

BootStrap学习笔记一: 学习工具:BootStrap中文文档:http://v3.bootcss.com/css/#type-lists <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- 为了让 IE 浏

Android 热修复 Tinker 源码分析之DexDiff / DexPatch

在上一篇文章中,我们介绍了Android 热修复 Tinker接入及源码浅析,里面包含了热修的一些背景知识,从tinker对dex文件的处理来看,源码大体上可以分为3部分阅读: 在应用中对patch的合并与加载,已经在上篇文章中详细介绍过了Android 热修复 Tinker接入及源码浅析 详细的dex patch,dex diff算法 tinker gradle plugin相关知识 tinker有个非常大的亮点就是自研发了一套dex diff.patch相关算法.本篇文章主要目的就是分析该算

BootStrap 学习笔记三

BootStrap学习笔记一: 学习工具:BootStrap中文文档:http://v3.bootcss.com/css/#type-lists 表格 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- 为了让 I