勘误:

原书(中文版)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. ./redis-trib.rb 报错:/usr/local/rvm/gems/ruby-2.4.2/gems/redis-4.0.1/lib/redis/client.rb:119:in `call': ERR Slot 0 is already busy (Redis::CommandError)

    错误提示是 slot插槽被占用了(这是 搭建集群前时,以前redis的旧数据和配置信息没有清理干净.) 解决方案是 用redis-cli 登录到每个节点执行  flushall  和 cluster ...

  2. winfroms更换皮肤

    一.添加控件lrisSkin.dll 然后把继承的窗体更换成别人做好的窗体类 能达到换肤的效果     二. 全部源代码就一行: skinEngine1.SkinFile = "WaveCo ...

  3. 用Vue的父子组件通信实现todolist的功能

    先上代码 <body> <div id="root"> <div> <input v-model="inputValue&quo ...

  4. hubilder 打包app ios高版本不支持问题

    <script type="text/javascript"> document.addEventListener('plusready', function(){ v ...

  5. Oracle之plsql及游标

    --1.赋值 --:= 赋值 declare var_name ) :='&请输入名字';--&是一个提示输入的特殊符号,会打开一个输入框 var_age ) :='&请输入年 ...

  6. redis学习指南

    一.redis安装 # 安装最新版 yum install -y epel-release vim atop htop net-tools git wget gcc-c++ yum clean all ...

  7. Python面向对象总结及类与正则表达式

    Python3 面向对象 一丶面向对象技术简介 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 方法:类中定义的函数. 类变 ...

  8. C语言/C++对编程学习的重要性!

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  9. golang 切片小记

    1 切片初始化 func printSlice(s []int) { fmt.Printf("len=%d cap=%d underlying array:%p, %v\n", l ...

  10. python学习笔记(二):基础知识点

    python基本元素 7 // 2 3 7 % 3 1 # 取商以及余数 divmod(7,3) (2, 1) 1j*1j (-1+0j) 10/3 3.3333333333333335 '3,''1 ...