疯狂的预编译加类型推导能孵化什么吗?
2013-09-04 15:25
218 查看
Boost 是个庞然大物,也许很多人已经把它用得很顺了,不过它包含的两个库 MPL 和 Preprocessor 应该大部分人都不会熟悉。
MPL 是用来进行模版元编程的工具,它将一些对象的推导工作做了抽象,可以把类型放入容器,在编译期实现一些很神奇的功能。
Preprocessor 为预编译提供了一系列的工具,帮助通过预编译来生成代码。
它们的结合帮助你在编译期实现很多强大的功能,最近研究它们小有心得,因此将我的 observer 做了些改动,添加了异步发送的能力。( observer 在
"优雅"的C++观察者模式实现 中有介绍)
借助 MPL 和 Preprocessor ,让 observer 使用时的语法相当的简洁,而由于它的实现基本都属于编译期,因此可以最大化的使用编译器来帮助查错,换句话说,只要编译能通过,一般情况下就没有错误。
用过 QT 的人应该对它的 信号与槽 印象深刻,遗憾的是,QT 槽和信号的实现需要QT自身的工具进行预编译,并且最让我讨厌的是,参数的错误在编译时是不会报错的,因此你调试的时候经常会发现某个槽无法触发,大大增加了查错的开销。而编译期的强类型匹配可以解决这个问题,只要编译通过,参数的数量、类型就肯定错不了。
PS: 目前版本的 MSVC 没有支持可变参模版,如果有了它,很多代码又可以简化了。
======================= 下面介绍一下 observer 的功能 =========================
这是一个观察者模式的简化实现,有助于代码的解耦。
你可以预先定义一些事件,事件的定义使用OBSERVER_EVENT宏:
OBSERVER_EVENT( Name, <Params> )
Name 是事件的名称
Params 是参数表
比如
OBSERVER_EVENT( MyEvent, int, std::string, long )
注:OBSERVER_EVENT 可以在类定义的内部使用的。
有必要的时候,就可以将一个回调函数绑定到这个事件(订阅)
observer a;
a.subscribe<Name>( Handle );
Name 是事件的名称
Handle 是回调函数,它的参数,应该和事件的参数表匹配
当然也可以撤销订阅
a.unsubscribe<Name>();
当事件发生时,可以通过 observer 对象来发送事件
a.shot<Name>( <Params> );
另外,也允许定义事件,并放入容器,以便延迟调用
lugce::event_base xx=new MyEvent( "hello" );
a.shot( xx );
这个对象可以作为基类使用,以帮助对象解耦,这样设计的优点在于,事件的定义、回调的参数表
必须严格匹配,否则就会发生编译错误,以防止代码错误。
特别的,参数可以定义为引用类型,以便让回调函数可以修改它,这时发送事件时,要注意使用 ref() 来包装参数。
observer 被收入 lugce 库中,svn 地址 https://svn.code.sf.net/p/lugce/code/ 。代码以 svn 为准。
MPL 是用来进行模版元编程的工具,它将一些对象的推导工作做了抽象,可以把类型放入容器,在编译期实现一些很神奇的功能。
Preprocessor 为预编译提供了一系列的工具,帮助通过预编译来生成代码。
它们的结合帮助你在编译期实现很多强大的功能,最近研究它们小有心得,因此将我的 observer 做了些改动,添加了异步发送的能力。( observer 在
"优雅"的C++观察者模式实现 中有介绍)
借助 MPL 和 Preprocessor ,让 observer 使用时的语法相当的简洁,而由于它的实现基本都属于编译期,因此可以最大化的使用编译器来帮助查错,换句话说,只要编译能通过,一般情况下就没有错误。
用过 QT 的人应该对它的 信号与槽 印象深刻,遗憾的是,QT 槽和信号的实现需要QT自身的工具进行预编译,并且最让我讨厌的是,参数的错误在编译时是不会报错的,因此你调试的时候经常会发现某个槽无法触发,大大增加了查错的开销。而编译期的强类型匹配可以解决这个问题,只要编译通过,参数的数量、类型就肯定错不了。
PS: 目前版本的 MSVC 没有支持可变参模版,如果有了它,很多代码又可以简化了。
======================= 下面介绍一下 observer 的功能 =========================
这是一个观察者模式的简化实现,有助于代码的解耦。
你可以预先定义一些事件,事件的定义使用OBSERVER_EVENT宏:
OBSERVER_EVENT( Name, <Params> )
Name 是事件的名称
Params 是参数表
比如
OBSERVER_EVENT( MyEvent, int, std::string, long )
注:OBSERVER_EVENT 可以在类定义的内部使用的。
有必要的时候,就可以将一个回调函数绑定到这个事件(订阅)
observer a;
a.subscribe<Name>( Handle );
Name 是事件的名称
Handle 是回调函数,它的参数,应该和事件的参数表匹配
当然也可以撤销订阅
a.unsubscribe<Name>();
当事件发生时,可以通过 observer 对象来发送事件
a.shot<Name>( <Params> );
另外,也允许定义事件,并放入容器,以便延迟调用
lugce::event_base xx=new MyEvent( "hello" );
a.shot( xx );
这个对象可以作为基类使用,以帮助对象解耦,这样设计的优点在于,事件的定义、回调的参数表
必须严格匹配,否则就会发生编译错误,以防止代码错误。
特别的,参数可以定义为引用类型,以便让回调函数可以修改它,这时发送事件时,要注意使用 ref() 来包装参数。
observer 被收入 lugce 库中,svn 地址 https://svn.code.sf.net/p/lugce/code/ 。代码以 svn 为准。
相关文章推荐
- 疯狂的预编译加类型推导能孵化什么吗?
- [疯狂Java]泛型:泛型的底层原理(类型擦除、原生类型、编译前检查)
- [疯狂Java]面向对象:多态、编译时类型、运行时类型、向上兼容、兼容下反转、instanceof
- 编译时推导函数调用约定、常量性、返回值、参数等函数类型特征
- NSString* testObject = [[NSData alloc] init];testObject 在编译时和运行时分别是什么类型的对象?
- NSString* testObject = [[NSData alloc] init];testObject 在编译时和运行时分别是什么类型的对象?
- NSString* testObject = [[NSData alloc] init];testObject 在编译时和运行时分别是什么类型的对象?
- C++编译时的类型推导
- Java千百问_06数据结构(010)_Class类型是什么
- VS2010 项目引用了项目/DLL文件,也写了Using,但是编译时提示:未能找到类型或命名空间名称
- 年收入50万美元的软件工程师做的是什么类型的工作?
- MySql数据库,对varchar类型字段str进行where str=0条件查询时,查询结果是什么
- php中资源类型是个什么东西?谈下个人认识
- uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型 - 大总结,看完全明白了
- C++中string类型的内部结构是什么?
- 弱类型、强类型、动态类型、静态类型语言的区别是什么?
- 对于GetLogicalDrives这个函数,返回一个32位的DWORD类型的值,前26位可以分别表示a-z盘,那后6位表示什么?
- 什么是mime类型
- Effective Modern C++ Item1 模板类型推导详解
- 什么是C语言中的条件编译?