勘误:

原书(中文版)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. 【luogu P1558 色板游戏】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1558 我知道三十棵线段树很暴力,可是我们可以状压啊. 颜色最多30,不会爆int 另外 吐槽评测机 #inc ...

  2. Centos 7下Nagios的安装及配置

    简介 Nagios 是一款自动化运维工具,可以协助运维人员监控服务器的运行状况,并且拥有报警功能.本文章将介绍其安装方法和详细的配置方法. nagios 监控服务应用指南 本地资源:负载,CPU,磁盘 ...

  3. 解决error possibly undefined macro AC_MSG_ERROR

    问题 出现如下缺少宏的问题 error: possibly undefined macro: AC_MSG_ERROR error: possibly undefined macro: AC_SUBS ...

  4. nRF5 SDK for Mesh(一) 介绍和下载源码

    一: 官网介绍地址:http://www.nordicsemi.com/Products/Bluetooth-low-energy/nRF5-SDK-for-Mesh Nordic offers a ...

  5. 用JavaScript编写简单斗地主效果Es6

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 轻量ORM-SqlRepoEx (十四)最佳实践之Dapper(1)

    简介:SqlRepoEx是 .Net平台下兼容.NET Standard 2.0人一个轻型的ORM.解决了Lambda转Sql语句这一难题,SqlRepoEx使用的是Lambda表达式,所以,对c#程 ...

  7. EJB到底是什么?---通俗易懂,简单明了

    EJB到底是什么?   1. 我们不禁要问,什么是"服务集群"?什么是"企业级开发"? 既然说了EJB 是为了"服务集群"和"企业 ...

  8. java核心技术-多线程之引导概念

    前两篇文章分别讲了,Java线程相关基础概念以及线程的内存模型,本节作为后续章节的引导,个人认为对于学习后面的只是还是比较重要.好了,既然说了多线程,那么首先要弄清以下几个问题: 1. 什么是多线程? ...

  9. python使用ctypes模块下的windll.LoadLibrary报OSError: [WinError 193] % 不是有效的 Win32 应用程序

    原因:python是64位的python,而windll.LoadLibrary只能由32位的python使用 参考: 64位Python调用32位DLL方法(一) 解决方法:使用32位的python ...

  10. 解决 Cydia 源显示空白的问题

    打开 Cydia 所有源都显示空白,没有任何插件,已安装的列表也显示空白,解决方法是下载 var.lib_tar 包 下载链接: https://pan.baidu.com/s/1jzJ8KehoBo ...