`
oldrev
  • 浏览: 230703 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
社区版块
存档分类
最新评论

D语言实现的variant

阅读更多
boost.variant 是安全、范型、基于栈的可识别联合容器,下面的代码是其在D语言中的等价实现。借助D语言强大的元编程能力,其与C++的版本相比,代码清晰,对类型安全有更大的保证。
  • boost.variant 文档:http://www.boost.org/doc/html/variant.html
  • boost.any 和 boost.variant 的区别与比较: http://www.boost.org/doc/html/variant/misc.html#variant.versus-any
cpp 代码
 
  1. // Module:  variant.d  
  2. // Author:  Oldrev (wstring#AT#gmail.com)  
  3. // License: BSD  
  4.   
  5. module variant;  
  6.   
  7. import std.typetuple;  
  8. import std.traits;  
  9. import std.stdio;  
  10.   
  11. private template MaxSizeImp(T, V...)  
  12. {  
  13.     static if(V.length > 0)  
  14.         private const int tailResult = MaxSizeImp!(V).result;  
  15.     else   
  16.         private const int tailResult = T.sizeof;  
  17.   
  18.     public const int result = T.sizeof > tailResult ? T.sizeof : tailResult;  
  19. };  
  20.   
  21. private template MaxSize(TList...)  
  22. {  
  23.     const int MaxSize = MaxSizeImp!(TList).result;  
  24. }  
  25.   
  26. struct Variant(TList...)  
  27. {  
  28.     public alias TList TypeList;  
  29.     public alias Variant!(TypeList) SelfType;  
  30.     private alias ubyte[MaxSize!(TypeList)] Holder;  
  31.   
  32.     private Holder  m_held;  
  33.     private int     m_which = -1;  
  34.   
  35.     public int which()  
  36.     {  
  37.         return m_which;  
  38.     }  
  39.   
  40.     public SelfType assign(ValueType)(ValueType val)  
  41.     {  
  42.         static if(is(ValueType == SelfType))  
  43.         { 
  44.             m_held[] = val.m_held[];
  45.             m_which = which;
  46.         }         
  47.         else  
  48.         {  
  49.             const int i = IndexOf!(ValueType, TypeList);  
  50.             static assert(i >= 0);  
  51.             ValueType* heldPtr = cast(ValueType*)m_held.ptr;  
  52.             *heldPtr = val;  
  53.             m_which = i;  
  54.         }  
  55.   
  56.         return *this;  
  57.     }  
  58.   
  59.     public SelfType opAssign(ValueType)(ValueType rhs)  
  60.     {  
  61.         return assign!(ValueType)(rhs);  
  62.     }  
  63.   
  64.     public bool opEquals(ValueType)(ValueType rhs)  
  65.     {  
  66.         assert(!empty);  
  67.   
  68.         static if(is(ValueType == SelfType))  
  69.         {  
  70.             foreach(T; TypeList)  
  71.             {  
  72.                 const int i = IndexOf!(T, TypeList);  
  73.                 if(i == which)  
  74.                 {  
  75.                     return (rhs.which == which) && (get!(T) == rhs.get!(T));  
  76.                 }  
  77.             }  
  78.         }  
  79.         else  
  80.         {  
  81.             const int i = IndexOf!(ValueType, TypeList);  
  82.             static assert(i >= 0);  
  83.           
  84.             return get!(ValueType)() == rhs;  
  85.         }  
  86.     }  
  87.   
  88.     public int opCmp(ValueType)(ValueType rhs)  
  89.     {  
  90.         if(rhs == *this)return 0;  
  91.         static if(is(ValueType == SelfType))  
  92.         {  
  93.             foreach(T; TypeList)  
  94.             {  
  95.                 const int i = IndexOf!(T, TypeList);  
  96.                 if((i == which) && (rhs.which == which))  
  97.                 {  
  98.                     return get!(T) < rhs.get!(T) ? -1 : 1;  
  99.                 }  
  100.             }  
  101.         }  
  102.         else  
  103.         {  
  104.             const int i = IndexOf!(ValueType, TypeList);  
  105.             static assert(i >= 0);  
  106.           
  107.             return get!(ValueType)() < rhs ? -1 : 1;  
  108.         }  
  109.     }  
  110.       
  111.     public TypeInfo type()  
  112.     {  
  113.         foreach(T; TypeList)  
  114.         {  
  115.             const int i = IndexOf!(T, TypeList);  
  116.             if(i == which)  
  117.             {  
  118.                 return typeid(TypeList[i]);  
  119.             }  
  120.         }  
  121.     }  
  122.   
  123.     public ValueType get(ValueType)()  
  124.     {  
  125.         assert(typeid(ValueType) == type);  
  126.         return *(cast(ValueType*)m_held.ptr);  
  127.     }  
  128.   
  129.     public bool empty()  
  130.     {  
  131.         return m_which < 0;  
  132.     }  
  133.   
  134.     public void swap(inout SelfType var)  
  135.     {  
  136.         Holder h;  
  137.         h[] = m_held;  
  138.         int w = which;  
  139.         m_held[] = var.m_held;  
  140.         m_which = var.which;  
  141.         var.m_held[] = h;  
  142.         var.m_which = w;  
  143.     }  
  144.   
  145.     public static SelfType opCall(ValueType)(ValueType val)  
  146.     {  
  147.         SelfType var;  
  148.         var = val;  
  149.         return var;  
  150.     }  
  151.   
  152. }  
  153.   
  154. void main()  
  155. {  
  156.     class Foo  
  157.     {  
  158.         public:  
  159.         int n = 0;  
  160.         int x = 0;  
  161.         int y = 0;  
  162.         int z = 0;  
  163.   
  164.         Foo opAssign(int rhs)  
  165.         {  
  166.             x = rhs;  
  167.             y = rhs;  
  168.             z = rhs;  
  169.             return this;  
  170.         }  
  171.     }  
  172.   
  173.     struct Bar  
  174.     {  
  175.         public:  
  176.         int x = 0;  
  177.         int y = 1;  
  178.         int z = 2;  
  179.     }  
  180.   
  181.     Variant!(doubleintchar[], Foo, Bar) v = 2; // DMD 0.177 new feature  
  182.     assert(v == 2);  
  183.     assert(v <= 2);  
  184.     v = 2.22;  
  185.     assert(v == 2.22);  
  186.     assert(v.type == typeid(double));  
  187.     v = new Foo;  
  188.     assert(v.type == typeid(Foo));  
  189.     v.get!(Foo)() = 2;  
  190.     assert(v.get!(Foo)().z == 2);  
  191.     typeof(v) v2 = v;  
  192.     assert(v2 == v);  
  193.     v = "Foobar".dup;  
  194.     assert(v == "Foobar".dup);  
  195.       
  196.     v.swap(v2);  
  197.     assert(v2.get!(char[])() == "Foobar");  
  198.       
  199.     Bar b;  
  200.     b.x = 10;  
  201.     v = b;  
  202.     assert(v.get!(Bar)().x == 10);  
  203.   
  204. }  
分享到:
评论
7 楼 oldrev 2007-03-16  
引用

这个实现可以稍稍优化一下,因为ValueType是在编译期可以知道的,所以可以用IndexOf确定它在TList中的位置,直接和which判断就行了,不用再调用type()函数。

我就是知道 assert 可以被屏蔽掉,所以才偷了个懒....

引用

另外断言只在debug环境下有效,如果是不兼容的类型,cast结果会是空指针,这时可能会出现一个段错误了。

对阿,这里应该用异常还是 assert 应该再仔细研究一下。
6 楼 oldrev 2007-03-16  
引用

不过这个opCast只能转到一种类型,可以自己实现多种类型的转换,当然也就用不了cast了:


C++ 的用户自定义类型转换操作符可以实现隐式转换,如:
operator double() const {...}

这个特性虽然方便但也很容易引起难以发现的 bug
5 楼 qiezi 2007-03-16  
     public ValueType get(ValueType)()  
     {  
         assert(typeid(ValueType) == type);  
         return *(cast(ValueType*)m_held.ptr);  
     } 

这个实现可以稍稍优化一下,因为ValueType是在编译期可以知道的,所以可以用IndexOf确定它在TList中的位置,直接和which判断就行了,不用再调用type()函数。

另外断言只在debug环境下有效,如果是不兼容的类型,cast结果会是空指针,这时可能会出现一个段错误了。
4 楼 qiezi 2007-03-16  
不过这个opCast只能转到一种类型,可以自己实现多种类型的转换,当然也就用不了cast了:

import std.stdio;

class Foo{
  int convert(T:int)(){return 3;}
  long convert(T:long)(){return 4;}
}

void main(){
  Foo f = new Foo;
  writefln(f.convert!(int));
  writefln(f.convert!(long));
}
3 楼 qiezi 2007-03-16  
可以呀,opCast就是了。。

http://digitalmars.com/d/operatoroverloading.html
2 楼 oldrev 2007-03-15  
为什么D不能重载类型转换操作符呢
1 楼 ideage 2007-03-07  
这个好东西也可以贡献到Tango了!发布到火星吧!

相关推荐

Global site tag (gtag.js) - Google Analytics