勘误:

原书(中文版)3.13节,65-69页中GenScatterHierarchy以及FieldHelper均存在问题,当TypeList中类型有重复时,无法通过编译(原因在于“二义性基类”)。

书中出现的二义性问题,可以用一小段代码演示一下:

class A{};
class B:public A{};
class C:public A,public B{}; void test()
{
C c;
A& cf =c;//wrong,don't try this at home.
B& cbf =c;//right
A& caf = cbf;//right
}

由于C继承了两个A,一个直接继承,一个间接继承,所以将C转换成A,存在两条路径,无法转换。甚至我们永远无法访问C直接继承的A!

继承B的路径是唯一的,所以可以通过B,再次转换成为A。

《C++设计新思维》书中给出的代码和类图,向右侧转换是唯一的,但是向左侧转换时路径不为一,所以TypeList一旦包含重复类型后,无法通过编译。

这个问题已经解决了,具体解决方案请参看Loki源码 Loki源码

这里我简要说一下,解决方法就是确保左端的直接父类是唯一的,这样即可有一条唯一的路径可以转换到某一基类。

C++14 新法:

首先,给出typelist和操作typelist的两个函数

template <typename... T> struct TypeList;

template <int I, typename Arg>
struct at;
template <int I, typename Head, typename... Tail>
struct at<I, TypeList<Head, Tail...>>
{
typedef typename at<I - , TypeList<Tail...>>::type type;
};
template <class Head, typename... Tail>
struct at<, TypeList<Head, Tail...>>
{
typedef Head type;
};
template <int N, class Seq>
struct drop;
template <int N, class Head, class... Tail>
struct drop<N, TypeList<Head, Tail...>>
{
typedef
typename drop<N-, TypeList<Tail...>>::type
type;
};
template <class Head, class... Tail>
struct drop<, TypeList<Head, Tail...>>
{
typedef TypeList<Head, Tail...> type;
};

at获取typelist中某个索引值的类型元素,而drop是去除首部的某几个元素。

下面给出GenScatterHierarchy代码,此处为了方便使用Genorator代之。

namespace Private
{
// The following type helps to overcome subtle flaw in the original
// implementation of GenScatterHierarchy.
// The flaw is revealed when the input type list of GenScatterHierarchy
// contains more then one element of the same type (e.g. LOKI_TYPELIST_2(int, int)).
// In this case GenScatterHierarchy will contain multiple bases of the same
// type and some of them will not be reachable (per 10.3).
// For example before the fix the first element of Tuple<LOKI_TYPELIST_2(int, int)>
// is not reachable in any way!
template<class, class>
struct UniqueTag;
} template <typename Head,typename... Tails, template <typename> class Unit> class Genorater<TypeList<Head,Tails...>,Unit>
:public Genorater<Private::UniqueTag<Head,TypeList<Head,Tails...>>,Unit>,public Genorater<TypeList<Tails...>,Unit> {};
template <typename Head,typename... Tails,template <typename> class Unit> class Genorater<Private::UniqueTag<Head,TypeList<Head,Tails...>>,Unit>:public Unit<Head> {};

UniqueTag,用于辅助构建唯一的类型转换路径。

下面给出FieldHelper源码:

template <int I,typename... TList,template <typename> class Unit> Unit<typename at<I,TypeList<TList...>>::type>& FieldHelper(Genorater<TypeList<TList...>,Unit>& obj)
{ Genorater<Private::UniqueTag<typename at<I,TypeList<TList...>>::type,typename drop<I,TypeList<TList...>>::type>,Unit>& leftBase = obj;
return leftBase; } template <int I,typename... TList, template <typename> class Unit> Unit<typename at<I,TypeList<TList...>>::type>& Field(Genorater<TypeList<TList...>,Unit>& obj)
{ //return FieldHelper(obj,Int2Type<I>());
return FieldHelper<I>(obj);
}

最后是测试代码:

typedef TypeList<double,int,double,string> myList;

typedef Genorater<myList,Holder> Info;

int main()
{
cout << "Hello world!" << endl; Info obj;
cout<<typeid(obj).name()<<endl;
Field<>(obj).value_=;
Field<>(obj).value_=;
Field<>(obj).value_="hao123";
cout<< Field<>(obj).value_<<endl;
cout<< Field<>(obj).value_<<endl;
cout<< Field<>(obj).value_<<endl; return ;
}

-------------------------------------------------------------------------华丽的分割线---------------------------------------------------------------------------------------

此处给出一个仿写Loki源码的FieldHelper

namespace Private
{
template<class, class...>
struct UniqueTag;
} template <typename Head,typename... Tails, template <typename> class Unit> class Genorater<TypeList<Head,Tails...>,Unit>
:public Genorater<Private::UniqueTag<Head,Tails...>,Unit>,public Genorater<TypeList<Tails...>,Unit> {};
template <typename Head,typename... Tails,template <typename> class Unit> class Genorater<Private::UniqueTag<Head,Tails...>,Unit>:public Unit<Head> {}; template <typename Head,typename... TList,template <typename> class Unit> Unit<Head>& FieldHelper(Genorater<TypeList<Head,TList...>,Unit>& obj,Int2Type<>){ Genorater<Private::UniqueTag<Head,TList...>,Unit>& leftBase = obj;
return leftBase;
}
template <int I,typename Head,typename... TList, template <typename> class Unit> Unit<typename at<I,TypeList<Head,TList...>>::type>& FieldHelper(Genorater<TypeList<Head,TList...>,Unit>& obj,Int2Type<I>){ Genorater <TypeList<TList...>,Unit>& rightBase = obj;
return FieldHelper(rightBase,Int2Type<I->());
}

补充一些内容,其实C++11可利用变模板参数而剔除typelist。比如C++11标准的tuple的实现并没有利用typelist技术。

tuple利用了多重继承,实现方法和Genorator方式大同小异。C++11采用左端采用公有继承,右端使用私有继承。并采用int类型模板参数,作为转换路径唯一的标示。

具体见C++11 tuple.h中 相关源码。

接下来我不使用typelist技术来实现单根继承

class empty{};

template <template <typename,typename> class Unit,typename Head,typename... Tail> class GenorateLiner
:public Unit<Head,GenorateLiner<Unit,Tail...>>{ }; template <template <typename,typename> class Unit,typename Head> class GenorateLiner<Unit,Head>:Unit<Head,empty>{ };

谢谢,转载请表明出处!本文仅对读过《C++设计新思维》一书朋友有用,其他博友慎读(不要对C++产生抵触情绪)

《C++设计新思维》勘误,附C++14新解法的更多相关文章

  1. 《C++设计新思维》Command设计模式读后感

    原文内容提领: 本书第5章标题为泛化仿函数,我认为本章真正讲述的内容可以总结出一句话! 如何利用C++老标准实现C++11新标准类似std::function提供的功能. std::function简 ...

  2. PowerBuilder编程新思维3:适配(三层架构与GraphQL)

    PowerBuilder编程新思维3:适配(三层架构与GraphQL) PB在富客户端时代,是一线开发工具.随着网络发展,主流架构演进到三层架构的时代,PB拿不出有力的三层架构,已经明显力不从心,市场 ...

  3. PowerBuilder编程新思维2:嵌入(Thread多线程)

    PowerBuilder编程新思维2:嵌入(Thread多线程) 在PB中使用多线程,在网上有大量的文章介绍.不过深入研究并试着给出更易用的模型的,目前还只有"路人甲cw"的一篇& ...

  4. MySQL 8.0.14 新的密码认证方式和客户端链接

    MySQL 8.0.14 新的密码认证方式和客户端链接 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   MySQL8.0在密码认证方式发生了改变,这也是有点小伙伴在MySQL创建 ...

  5. PowerBuilder编程新思维5:包装(界面美化与WebUI+React)

    PowerBuilder编程新思维5:包装(界面美化与WebUI+React) 前一节,分析了三种界面美化方案,都是控件级的美化.今天再来分析一下窗口级的美化.上一次讲的DirectUI,大家反响一般 ...

  6. PowerBuilder编程新思维4:钩挂(界面美化与DirectUI)

    <第二部分 Outside> PowerBuilder编程新思维4:钩挂(界面美化与DirectUI) PB的界面由于其封闭性,一直以来都是最大的弱项.自PB9.0开放了PBNI接口后,开 ...

  7. PowerBuilder编程新思维1:扩展(Lua)

    前言 PowerBuilder作为开发工具退出一线行列已经很久了,在2019年来谈这样一款老旧的编程工具是否有意义?诚然,PB有着太多硬伤,但还是有它的用武之地的.而且今天讲的这个“新思维”大部分内容 ...

  8. FS系统开发设计(思维导图)

      FS系统开发设计(思维导图) 最近做了一个小系统,公司应急,要对各个部门进行费用成本核算分摊,做运维,苦于无奈,简简单单的设计了一下,模仿用友ERP软件,首先对DB进行了初步设计,总体如下: 未完 ...

  9. 基于事件驱动的DDD领域驱动设计框架分享(附源代码)

    原文:基于事件驱动的DDD领域驱动设计框架分享(附源代码) 补充:现在再回过头来看这篇文章,感觉当初自己偏激了,呵呵.不过没有以前的我,怎么会有现在的我和现在的enode框架呢?发现自己进步了真好! ...

随机推荐

  1. 安装Centos 7 错误解决

    dracut-initqueue[624]:Warning: Could not boot. dracut-initqueue[624]:Warning: /dev/root does not exi ...

  2. 【转】上传jar包到nexus私服

    原文:https://my.oschina.net/lujianing/blog/297128 1通过网页上传 这种方法只是上传了jar包.通过maven引用当前jar,不能取得jar的依赖 from ...

  3. 3.Spring Cloud初相识--------Ribbon客户端负载均衡

    前言: 在生产环境中,未避免单点故障,每个微服务都会做高可用部署. 通白的说,就是每一个一模一样的服务会根据需求提供多分在多台机器上. 那么在大并发的情况下,如何分配服务可以快速得到响应,就成为了我们 ...

  4. iOS之LLDB调试器

    LLDB被定位为下一代的高性能调试器,默认内置于Xcode IDE内, 支持在PC.iOS设备以及模拟器上调试C.Objective-C和C++. 关于LLDB的官方介绍:LLDB 常用命令: 1.  ...

  5. Druid手动设置参数错误

    在做Druid操作的时候,出现了小错误:但是总归是找到了,并且推一及三,以后学者高效解决问题: 严重: create connection errorjava.sql.SQLException: Ac ...

  6. JS常见算法题目

      最近收集了几个经典JS题目,比较有代表性,分享一下:   1.xiaoshuo-ss-sfff-fe  变为驼峰xiaoshuoSsSfffFe function getCamelCase(str ...

  7. Innodb和Mysiam引擎的区别

    一:区别 Mysiam: 1.是非事务安全型. 2.是表级锁. 3.如果执行大量的select,Mysiam是更好的选择. 4.select count(*)from table.Mysiam只简单的 ...

  8. Mariadb相关

    centos下Mariadb相关 MariaDB 是一个采用 Maria 存储引擎的MySQL分支版本,是由原来 MySQL 的作者Michael Widenius创办的公司所开发的免费开源的数据库服 ...

  9. Vue 父组件调用子组件的方法

    qwq  前两天看了下vue,父子组件方法的调用,怕忘记,所以做个小记录. 一.父组件调用子组件的方法 1.父组件 <template> <div id="rightmen ...

  10. MongoDB 数据类型查询 — $type使用

    MongoDB 使用过程中经常需要根据字段的类型来查询数据, 而MongoDB中查询字段类型是通过$type操作符来实现. $type使用法语: db.集合名.find({$type:类型值}); / ...