`

TypeList

    博客分类:
  • c++
阅读更多

 

转自:http://blog.csdn.net/hhygcy/article/details/3339176

其他:http://blog.csdn.net/gxut555/article/details/7454329

 

    假设你有若干个类,现在你希望给每个类分配一个唯一的ID。最简单的方法无非是手工的为这个类添加一个id,前提是你确信给这个类的id与其它类的id没有冲突,为此你需要查看其它所有类的代码。

    稍微好一点的办法是使用GUID产生器产生的GUID,这样就可以保证每个类的id都是唯一的了。但是GUID128位的长度似乎又有一些浪费。

    其实还有这样的一个思路:我们到一个地方将这些类进行注册,注册的同时返回一个数值作为类的id。那么用什么作为这些类进行注册的容器呢?

    Loki库中的TypeList就是一个理想的选择。TypeList就象一个普通的List,但是它里面“存储”的是一个一个的Type,而不是具体的数据(其实TypeList是借助模板元编程实现的,所以在编译之后,TypeList也就不存在了,因此“存储”二字需要加上引号)。

    我们可以将所有的类都添加到TypeList中,然后使用IndexOf返回每个类在TypeList中的索引,从而达到取得唯一ID的目的。

 

 

套用一个现在很流行的句式,(好多什么编程之美或者代码之美的)。我想看了第三章Modern C++ Design能感受的就是递归之美。而其中主要介绍的TypeList就是这样一个递归演绎的完美的例子。

 

其实TypeList本身的定义非常简单。就是一个有Head有Tail的一个简单的空的定义

template

struct Typelist

{

typedef T Head;

typedef U Tail;

};

但是如果加上一下这一组宏定义,这个原来的定义就可以无限延伸了

 

#define LOKI_TYPELIST_1(T1) ::Loki::Typelist

#define LOKI_TYPELIST_2(T1, T2) ::Loki::Typelist

#define LOKI_TYPELIST_3(T1, T2, T3) ::Loki::Typelist

 

当 然这里的Loki就是本书主要介绍的Loki Library.的名字空间。用过这样的递归的调用你就可以创建出类似的LOKI_TYPELIST_50甚至LOKI_TYPELIST_100。当让 可以让他变的更为强大,强大到随意的添加一个新的类,删除其中的一个类,或者删除冗余的重复。

我们从简单的来看先:

 

template struct Length;

template <> struct Length

{

enum { value = 0 };

};

 

template

struct Length<> >

{

enum { value = 1 + Length::value };

};

 

这 里的实现处处投射出递归的思想,Length这样的模板如何显示出value呢。如果TList是NullType的时候(NullType是这里定义的 一个表示空的类,前面章已有说明),那长度就是0,慢慢来, 如果这个TypeList是TypeList,可以看到value = 1 + Length::value,也就是1。 当然如果是LOKI_TYPELIST_x定义的类就返回LOKI_TYPELIST_(x-1)的长度加上1。这样的实现通过反复的去头操作实现。(就 是去掉TypeList中的T来实现)这样的操作后面还有非常多。

 

template struct TypeAt;

 

template

struct TypeAt, 0>

{

typedef Head Result;

};

 

template

struct TypeAt, i>

{

typedef typename TypeAt::Result Result;

};

 

TypeAt 这个模板用来提取出这个TypeList中某个Index对应的类,非常直观。类似的如果index是0,就返回当前这个TypeList的Head,就 是第一个类对应的类型。如果是非0的i呢?就和第一个定义一样,去掉Head以后,再找整个TypeList中从Tail第一项开始的第i-1个。递归, 还是递归。这样的定义随处可见。真很佩服Andrei Alexandrescu。天才,真是天才!随着看这本书的深入,越来越觉得自己的苍白,好像从来没有学会C++过。

继续来看写稍微复杂点的定义。

 

template struct IndexOf;

 

template

struct IndexOf

{

enum { value = -1 };

};

 

template

struct IndexOf, T>

{

enum { value = 0 };

};

 

template

struct IndexOf, T>

{

private:

enum { temp = IndexOf::value };

public:

enum { value = (temp == -1 ? -1 : 1 + temp) };

};

 

这 个定义乍一看还真有点迷糊, 不过仔细分析看看就明了了。慢慢分析,如果这个TypeList是空的话,那就返回-1,表示不包含这个T, 如果第一个就是T的话,那就返回0这样的index。这样的流程也符合一般的写递归的流程,先找到收敛条件,然后在逐次递归:) 如果第一个是Head,还不是T那怎么办呢,我们这个value就是取决与temp,而temp的取得呢是靠从Tail开始的这个list中的 value,如果在IndexOf中没有找到T,那value就是一个是-1,那TypeList的value也就是-1,因为没有。如果能找到那之前的 value至少是0开始的,就可以依次往上加1。现在看还挺清楚的了。

就是这样的一段段的定义可以定义出这么一大陀的东西:

template struct Length;

template struct TypeAt;

template struct IndexOf;

template struct Append;

template struct Erase;

template struct EraseAll;

template struct NoDuplicates;

template struct Replace;

template struct ReplaceAll;

template struct Reverse;

template struct MostDerived;

template struct DerivedToFront;

 

可是有了这些个定义有什么用呢??这是一个Good Question。这样的模式可以帮助我们毫不费力的创建出一些列的满足特定需求的类

 

template class Unit>

class GenScatterHierarchy;

// GenScatterHierarchy specialization: Typelist to Unit

template class Unit>

class GenScatterHierarchy, Unit>

: public GenScatterHierarchy

, public GenScatterHierarchy

{

public:

typedef Typelist TList;

typedef GenScatterHierarchy LeftBase;

typedef GenScatterHierarchy RightBase;

};

// Pass an atomic type (non-typelist) to Unit

template class Unit>

class GenScatterHierarchy : public Unit

{

typedef Unit LeftBase;

};

// Do nothing for NullType

template class Unit>

class GenScatterHierarchy

{

};

 

template 

struct Holder

{

T value_;

};

typedef GenScatterHierarchy WidgetInfo;

就像书中给出的这个例子一样。GenScatterHierarchy的定义结合了TypeList的优势,一个简单的一定WidgetInfo就定义出了至少这些个类: Holder,Holder和Holder而且还有一定的继承关系, 显然他们WidgetInfo继承自他们。

所以这样的语句就很自然了

WidgetInfo obj;

string name = (static_cast&>(obj)).value_;

神奇吧。更厉害的是可以把GenScatterHierarchy这个分散的(scattered)继承关系变为线性的。那就是GenLinearHierarchy了,这个就不具体讲了,相信以后具体介绍Loki里面容器设计的时候还会设计到的。今天就到这里吧。

 

 

#include <stdio.h>

struct NullType;
template <typename T0 = NullType, typename T1 = NullType, typename T2 = NullType,
          typename T3 = NullType, typename T4 = NullType, typename T5 = NullType>
struct typelist
{
    typedef T0 Head;
    typedef typelist<T1, T2, T3, T4, T5> Tail;
    enum { length = 1 + Tail::length };
};
template <>
struct typelist<NullType, NullType, NullType, NullType, NullType, NullType>
{
    enum { length = 0 };
};
template <typename TL, int n, bool OutOfRange = (n >= TL::length)>
struct type_at
{
    typedef typename type_at<typename TL::Tail, n-1>::type type;
};
template <typename TL>
struct type_at<TL, 0, false>
{
    typedef typename TL::Head type;
};
template <typename TL, int n>
struct type_at<TL, n, true>
{
};
template <typename T, typename U>
struct is_same_type
{
    enum { value = false };
};
template <typename T>
struct is_same_type<T, T>
{
    enum { value = true };
};
template <typename TL, typename T, int count = -1, bool equalsHead =
          is_same_type<typename TL::Head, T>::value>
struct index_of
{
    enum { value = 1 + index_of<typename TL::Tail, T, count-1>::value };
};
template <typename TL, typename T, int count>
struct index_of<TL, T, count, true>
{
    enum { value = 0 };
};
template <typename T, typename U, int count>
struct index_of<typelist<T>, U, count, false>
{
    enum { value = count };
};
template <typename T, typename U, bool greaterThan = (sizeof(T) >= sizeof(U))>
struct type_selector
{
    typedef T type;
};
template <typename T, typename U>
struct type_selector<T, U, false>
{
    typedef U type;
};
template <typename TL>
struct largest_type
{
    typedef typename type_selector<typename TL::Head, typename largest_type<typename
            TL::Tail>::type>::type type;
};
template <typename T>
struct largest_type<typelist<T> >
{
    typedef T type;
};
int main()
{
    typedef typelist<int, float, double, char> types;
    printf("%d\n", types::length);
    type_at<types, 3>::type ch = 'c';
    printf("%c\n", ch);
    printf("%d\n", index_of<types, unsigned>::value);
    printf("%d\n", index_of<types, double>::value);
    largest_type<types>::type d = 2.5;
    printf("%lf\n", d);
    printf("%d\n", index_of<types, largest_type<types>::type>::value);
}

 #include <stdio.h>

#include <typeinfo.h>
//
// TypeList
//
template <class T, class U>
struct TypeList
{
    typedef T Head;
    typedef U Tail;
};

struct NullType
{
};

#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) >

//
// Length
//
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};
};

//
// TypeAt
//
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 index>  struct TypeAt< TypeList<Head,Tail>,index >
{
    typedef typename TypeAt<Tail, index-1>::Result Result;
};

//
// IndexOf
//
template <class TList, class T>  struct IndexOf;

template <class T>  struct IndexOf< NullType, T >
{
    enum {value = -1};
};
template <class T,class Tail>  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>::value };
public:
    enum { value = temp==-1 ? -1 : 1 + temp};
};


//
// Append
//
template <class TList, class T>  struct Append;

//
// push_front
//
template <class TList, class T>  struct push_front
{
    typedef TypeList<T, >
};

int main(int argc, char *argv[])
{
    printf("Hello, world\n");

    typedef TYPELIST_3(int, float,char) MyTypeList;
    printf("MyTypeList length %d\n", Length<MyTypeList>::value);

    printf("MyTypeList TypeAt 0 %s\n", typeid(TypeAt<MyTypeList,0>::Result).name());
    printf("MyTypeList IndexOf<int> %d\n", IndexOf<MyTypeList, float>::value);

    return 0;
}
分享到:
评论

相关推荐

    TensorRT加速的YOLOv5智能监控平台:多线程多任务并行处理,视频监控与录像回放一体化管理

    内容概要:本文详细介绍了如何使用TensorRT加速YOLOv5模型推理,并结合QT框架搭建一个多任务并行处理的智能监控平台。主要内容包括:YOLOv5与TensorRT的融合,通过将YOLOv5模型转换为ONNX格式并进一步转化为TensorRT引擎,从而大幅提升推理速度;QT框架的应用,利用其跨平台特性实现视频监控、录像回放、电子地图等多种功能;16路视频并行检测的具体实现,通过多线程机制和CUDA流的支持,确保系统的高效运行。此外,文章还探讨了模型热更新、网络流处理、日志记录等方面的优化措施。 适合人群:具备一定编程基础,尤其是熟悉C++、Python和深度学习框架的研究人员和技术开发人员。 使用场景及目标:适用于需要高效、智能监控解决方案的企业和个人开发者。主要目标是提高视频监控系统的效率和智能化水平,如安防监控、交通监测等领域。 其他说明:文中提供了大量代码示例,帮助读者更好地理解和应用所介绍的技术。同时强调了系统设计中的性能优化技巧,如内存管理和多线程调度等。

    JiYuTrainer

    反极域和远程机惨的好工具

    基于Matlab GUI界面的电子双缝衍射实验模拟:缝宽、间距、电压与距离的参数设置与电子数目影响研究

    内容概要:本文详细介绍了如何利用MATLAB的GUI界面模拟电子双缝衍射实验。通过创建自定义的GUI界面,用户可以输入缝宽a、双缝间距b、加速电压U、缝屏距离D以及电子数目n等参数,实时观察衍射图样的变化。文中不仅提供了详细的代码实现步骤,还解释了各个参数对衍射图样的具体影响,如缝宽a的变化会影响条纹宽度,加速电压U的变化会影响条纹间距等。此外,文章还讨论了一些特殊情况下(如缝间距过大)的非预期现象及其背后的物理原因。 适合人群:物理学专业学生、教师以及对量子力学感兴趣的科研工作者。 使用场景及目标:①作为教学辅助工具,帮助学生更直观地理解电子双缝衍射实验及其背后的物理原理;②作为一种研究手段,探索不同参数条件下电子双缝衍射的具体表现形式。 其他说明:作者提醒使用者不要将电子数目n设得过高以免造成程序运行缓慢,并指出了一些常见的错误配置可能导致的异常情况。同时,提供了一个GitHub链接供有兴趣的读者进一步探讨和改进。

    实训商业源码-qui-pure.v2.5-毕业设计.zip

    实训商业源码-qui-pure.v2.5-毕业设计.zip

    scratch少儿编程逻辑思维游戏源码-有弹性的…猫.zip

    scratch少儿编程逻辑思维游戏源码-有弹性的…猫.zip

    汇川H3U标准程序:三轴伺服定位与总线控制,模块分明,清晰案例示范,包含多种定位与点动操作

    内容概要:本文详细介绍了汇川H3U系列可编程控制器在多轴伺服定位控制方面的应用案例。文章分为三个主要部分:一是本体脉冲控制的三轴伺服定位,展示了通过梯形图实现脉冲输出控制轴运动的方法;二是总线控制的16轴汇川伺服定位,利用结构体数组管理和初始化多个轴的数据,实现了高效的总线通信;三是具体的功能实现,包括轴点动、回零、相对定位与绝对定位等功能的代码示例及其工作原理。此外,文中强调了模块化设计的重要性,通过合理的分层架构提高了系统的灵活性和稳定性。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对伺服控制系统感兴趣的初学者和有一定经验的研发人员。 使用场景及目标:适用于需要理解和掌握多轴伺服定位控制原理的实际工程项目中,旨在帮助读者深入理解汇川H3U控制器的工作机制,掌握具体的编程技巧,以便更好地应用于实际生产环境。 其他说明:文章不仅提供了详细的代码示例,还分享了许多宝贵的实践经验,如状态机的应用、异常处理机制等,这些都是提高程序可靠性的关键因素。

    【数字电路设计】二进制比较器原理与实现:基于74LS85芯片的多位数值比较系统构建及位数扩展方法探讨

    内容概要:本文详细介绍了二进制比较器的设计原理与实现方法。文章首先讲解了二进制比较器的基本概念,包括32位数字比较器的原理图绘制方法。文中提到可以使用二进制比较芯片(如74LS85)组合实现大于、等于、小于的功能,其中不等是通过大于和小于的或逻辑并归实现,大于则是芯片固有的功能,小于等于则是等于和小于的或逻辑并归。对于门电路合成,文章提到了使用74LS04D+08+86等元件组成一位二进制比较器,但指出位数增加会使逻辑变得复杂,不推荐自行合成。此外,还介绍了2位二进制比较器的工作原理,当高位不同时无需比较低位,只有当高位相同时才需要比较低位。最后,文章讨论了集成数值比较器74LS85的功能及其位数扩展方式,包括串联和并联两种扩展方法。 适合人群:具有一定的数字电路基础,对二进制比较器感兴趣的电子工程学生或工程师。 使用场景及目标:①理解二进制比较器的基本原理和工作方式;②掌握二进制比较器的硬件实现方法,特别是如何利用现有芯片构建多位比较器;③学习如何通过逻辑门电路实现简单的二进制比较功能。 阅读建议:读者在学习过程中应结合实际电路图和逻辑表达式进行理解和验证,特别是对于不同位数的二进制比较器,可以通过实际搭建电路来加深理解。

    实训商业源码-昂图文10.2.20 公众号版-毕业设计.zip

    实训商业源码-昂图文10.2.20 公众号版-毕业设计.zip

    【SAR图像变化检测】多阶多水平连接异质图SAR图像变化检测【含Matlab源码 4669期】.md

    【实用脚本工具】相关内容与技巧的【VIP资源】,包

    scratch少儿编程逻辑思维游戏源码-宇宙幽灵 Boss 之战.zip

    scratch少儿编程逻辑思维游戏源码-宇宙幽灵 Boss 之战.zip

    基于S7-200 PLC与组态王技术的机械手搬运控制系统详解:梯形图程序、接线图与组态画面全解析

    内容概要:本文详细介绍了基于西门子S7-200 PLC和组态王的机械手搬运控制系统的实现方案。首先,文章展示了梯形图程序的关键逻辑,如急停连锁保护、水平移动互锁以及定时器的应用。接着,详细解释了IO分配的具体配置,包括数字输入、数字输出和模拟量接口的功能划分。此外,还讨论了接线图的设计注意事项,强调了电磁阀供电和继电器隔离的重要性。组态王的画面设计部分涵盖了三层画面结构(总览页、参数页、调试页)及其动画脚本的编写。最后,分享了调试过程中遇到的问题及解决方案,如传感器抖动、输出互锁设计等。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC编程和组态软件有一定基础的读者。 使用场景及目标:适用于自动化生产线中机械手搬运控制系统的开发与调试。目标是帮助读者掌握从硬件接线到软件逻辑的完整实现过程,提高系统的稳定性和可靠性。 其他说明:文中提供了大量实践经验,包括常见的错误和解决方案,有助于读者在实际工作中少走弯路。

    MATLAB声发射波形分析:计算基本与特征参数并绘制单边振幅谱

    内容概要:本文详细介绍了如何使用MATLAB对声发射波形进行参数计算和单边振幅谱绘制。主要内容涵盖声发射波形的基本参数(如峰值振幅、上升时间和持续时间)、特征参数(如均方根振幅和能量)的计算方法,以及通过快速傅里叶变换(FFT)绘制单边振幅谱的具体步骤。文中提供了详细的MATLAB代码示例,帮助读者理解和实现这些操作。 适合人群:从事材料科学、无损检测等相关领域的研究人员和技术人员,尤其是有一定MATLAB基础的用户。 使用场景及目标:适用于需要对声发射信号进行深入分析的研究项目,旨在提高对声发射事件的理解和诊断能力。具体应用场景包括但不限于材料疲劳测试、结构健康监测等。 其他说明:文中还提到了一些实用技巧,如处理复数信号、使用窗函数减少频谱泄漏、去除直流分量等,有助于提升数据分析的准确性。此外,建议将整个分析流程封装成函数以便于重复使用。

    scratch少儿编程逻辑思维游戏源码-寻觅故事者.zip

    scratch少儿编程逻辑思维游戏源码-寻觅故事者.zip

    scratch少儿编程逻辑思维游戏源码-希望奔跑.zip

    scratch少儿编程逻辑思维游戏源码-希望奔跑.zip

    三相交流调压技术:探究触发角变化与带中性线桥式半控整流电路仿真中的波形差异

    内容概要:本文深入探讨了单相和三相交流调压技术,详细介绍了这两种技术的工作原理、应用场景以及波形变化规律。首先,文章解释了单相交流调压的基本概念,即通过对单一相位的交流电进行触发角调整来实现电压调节。接着,重点讨论了三相交流调压的特点,特别是在带有中性线的情况下,它能提供更稳定的参考点并支持复杂的工业应用。此外,文中还涉及了桥式半控整流电路的仿真实验,展示了不同触发角和负载条件下的波形变化情况。最后,文章展望了未来交流调压技术面临的挑战和发展机遇。 适合人群:从事电力电子相关行业的技术人员、研究人员及高校师生。 使用场景及目标:帮助读者深入了解单相和三相交流调压技术的具体实现方式,掌握波形变化规律,提升实际操作能力。 其他说明:文章结合理论与实践,既包含了基础知识介绍又涵盖了最新的研究成果和技术趋势。

    实训商业源码-【超人】商家联盟 3.2.2-毕业设计.zip

    实训商业源码-【超人】商家联盟 3.2.2-毕业设计.zip

    (Go)golang语言,window系统下安装go1.23.8语言包安装包

    Go语言,通常被称为Golang,是由Google开发的一种静态类型的、编译式的、并发型且具有垃圾回收功能的编程语言。它的设计目标是提高开发者的生产力和程序的运行效率,特别适合构建网络服务和分布式系统。在Windows操作系统下,安装Golang开发环境需要下载相应的安装包。这里提供的"Go开发工具,golang IDE安装包,windows系统下"包含了Golang的集成开发环境(IDE)——Goland以及相关的使用说明。 Goland是一款由JetBrains公司推出的专门针对Go语言的高效开发工具,它为Go开发者提供了强大的代码补全、调试、重构和代码审查等功能。Goland-2018.3.exe是该IDE的一个特定版本,可能包含了2018年第三季度的一些更新和改进,用户可以通过执行这个可执行文件来安装Goland。 在安装过程中,用户通常需要选择安装路径,确认是否添加到PATH环境变量,以便在命令行中直接使用go命令。安装完成后,Goland会自动检测并配置Go的编译环境,包括设置GOROOT(Go语言的安装目录)和GOPATH(工作区路径),这对于新手来说是非常方便的。 同时,压缩包中的"golang说明.txt"文件很可能是对如何使用Golang进行开发,以及如何操作Goland IDE的基本指导。这份文件可能涵盖了如何创建新项目、设置Go环境变量、使用内置的包管理器go mod、运行和调试程序等内容。对于初学者来说,这是理解并快速上手Go语言开发的重要参考资料。 在使用Golang进行开发时,有几个关键概念是需要了解的: 1. **GOPATH**:在早期版本中,GOPATH是存放项目源码、编译后的对象文件和第三方包的地方。从Go 1.11版本开始,引入了go modules,但理解GOPATH仍然有助于理解Go的工作方式。 2. **Go Mod

    scratch少儿编程逻辑思维游戏源码-西利斯通城堡.zip

    scratch少儿编程逻辑思维游戏源码-西利斯通城堡.zip

    西门子PLC1200博途V16程序详解:制药厂生物发酵系统工艺案例——涉及报警、模拟量处理、温度PID及数字量控制等自动化技术 注:电气控制原理图辅助参考,博图版本需V15.1及以上打开。

    内容概要:本文详细介绍了西门子PLC1200博途V16在制药厂生物发酵系统中的应用,涵盖硬件组态、报警功能、模拟量标定、温度PID控制以及称重仪表USS通讯等方面。硬件方面,采用ET200SP模块进行分布式I/O控制,称重仪表通过USS协议与PLC通信。软件方面,通过OB组织块、自定义数据块和函数块实现报警管理、模拟量处理、PID控制等功能。文中还提供了具体的代码示例,展示了如何处理报警、标定模拟量、实现PID控制和USS通讯。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对西门子PLC编程有一定基础的人群。 使用场景及目标:适用于制药厂生物发酵系统的自动化控制项目,帮助工程师理解和掌握PLC编程技巧,提高系统的稳定性和可靠性。具体应用场景包括但不限于:报警管理、模拟量处理、温度控制和称重仪表通讯等。 其他说明:本文不仅提供了详细的代码示例,还分享了许多实际工程中的经验和技巧,如PID参数调整、USS通讯调试、硬件组态注意事项等。对于初学者来说,这是一个很好的学习资料,能够帮助他们在实践中快速成长。

    【车道线检测】Hough变换和消失点车道线检测(判断左转 直行)【含Matlab源码 4084期】.md

    硬件开发教程&案例&相关项目资源,奖励仅限VIP资源

Global site tag (gtag.js) - Google Analytics