首页 > 代码库 > 《C++设计新思维》勘误,附C++14新解法
《C++设计新思维》勘误,附C++14新解法
勘误:
原书(中文版)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 - 1, TypeList<Tail...>>::type type;};template <class Head, typename... Tail>struct at<0, 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-1, TypeList<Tail...>>::type type;};template <class Head, class... Tail>struct drop<0, 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<1>(obj).value_=1; Field<2>(obj).value_=2; Field<3>(obj).value_="hao123"; cout<< Field<1>(obj).value_<<endl; cout<< Field<2>(obj).value_<<endl; cout<< Field<3>(obj).value_<<endl; return 0;}
-------------------------------------------------------------------------华丽的分割线---------------------------------------------------------------------------------------
此处给出一个仿写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<0>){ 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-1>());}
谢谢,转载请表明出处!本文仅对读过《C++设计新思维》一书朋友有用,其他博友慎读(不要对C++产生抵触情绪)
《C++设计新思维》勘误,附C++14新解法