`
oldrev
  • 浏览: 233740 次
  • 性别: 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了!发布到火星吧!

相关推荐

    R语言和C#混合编程

    本文将深入探讨如何利用R语言和C#进行混合编程,并通过一个名为R(D)COMServer的组件实现这一目标。 #### 二、R(D)COMServer介绍 R(D)COMServer是由Vienna University of Technology和University of Vienna联合开发...

    VB 动态数组的实现

    与C/C++等语言能够直接通过指针操作来实现内存的动态分配不同,VB 缺乏原生支持这种灵活的数组管理方式。这就意味着开发者在编写程序时可能会遇到如下的问题: 1. **数组大小预估困难**:在声明数组时,如果预先...

    lang

    在D语言中,XML DOM允许程序员通过对象模型来访问和操作XML数据,从而实现读取、修改和创建XML文档。XML DOM为D语言开发者提供了一种结构化的访问方式,可以方便地遍历XML节点、查找特定信息、修改元素属性等。这在...

    VB011-求一元二次方程的根

    在VB011-求一元二次方程的根这个主题中,我们主要探讨的是如何使用Visual Basic(VB)编程语言来解决数学中的一元二次方程。一元二次方程是形如ax² + bx + c = 0的方程,其中a、b和c是常数,a不等于0。解决此类方程...

    vc6.0MFC串口通信编写全过程

    本文将详细介绍使用VC6.0 MFC编程语言实现串口通信的全过程,涵盖串口调试助手的编辑过程、新建工程、添加控件、编辑控件、编程步骤等方面的知识点。 一、串口调试助手编辑过程 在VC6.0 MFC中,新建一个MFC ...

    VBA字典精简教程带范例

    VBA(Visual Basic for Applications)是Microsoft Office套件中用于自动化和编程的一种语言,它允许用户在Excel、Word等应用程序中编写自定义脚本,实现更复杂的功能。VBA字典对象是VBA中非常实用的数据结构之一,...

    多个word合并

    本文主要介绍如何使用Java语言结合第三方库`jacob.jar`来实现多个Word文档的合并功能。 #### 二、核心知识点解析 1. **Jacob库简介**: - Jacob (Java COM Bridge) 是一个开源库,它允许Java程序通过COM接口调用...

    Word批量转换TXT(java)

    Java作为一种强大的编程语言,提供了多种方式来实现这个需求。本篇将深入探讨如何利用Java库JACOB进行Word到TXT的批量转换。 JACOB(Java COM Bridge)是一个Java到COM接口的桥梁,它允许Java程序调用Windows的COM...

    餐厅管理信息系统课程设计

    工程使用的是基于对话框的程序,每个对话框为一个类,父类为CDialog,实现的一些功能都封装在类的函数中,体现了面向对象编程语言C++的特性。 导入ADO接口:在工程的stdafx.h文件里直接引入符号#import引入ADO库文件...

    基于EXCEL的ACCESS数据库报表程序的实现

    随着信息技术的发展,特别是Microsoft Office组件如Excel的强大功能以及Visual C++(VC)这样的高级编程语言的应用,可以有效地解决这一问题。本文旨在介绍如何利用VC结合ActiveX Data Objects (ADO)技术访问...

    2021-2022计算机二级等级考试试题及答案No.3583.docx

    实现关系通常在面向对象语言中指的是接口或抽象类的实现。 6. **循环计算**: - 给定的VBScript程序段在Command1_Click事件中,当i=20时,x的值为x+i,即8+20,因此最后`x`的值为28,选项D是正确答案。 7. **微机...

    PythonForDelphi for Python3.7 delphi7

    例如,Delphi的Variant类型可以直接映射到Python的任意类型,这在跨语言交互中非常有用。 在调用Python代码时,可以使用TPythonEngine的Execute方法来运行Python脚本,或者通过ExecuteMethod来调用已定义的Python...

    ASP期末考试试题.pdf

    13. **ASP脚本语言**:ASP文件中可以设置默认脚本语言,但仍可使用其他脚本,选项D错误。 14. **VBScript特性**:VBScript只有一种数据类型,即Variant,选项A正确。VBScript中变量无需先声明即可使用,选项C错误,...

    vb:vb(variant blast)询问hapx档案以进行直系同源序列变异

    VB(Variant Blast)是一种在生物信息学领域中用于检测序列变异的工具,它结合了变体查询和BLAST(Basic Local Alignment Search Tool)的功能。在本案例中,我们讨论的是如何利用VB对hapx文件进行操作,寻找直系...

    wordtohtml

    ### WordToHtml 转换工具知识点解析 #### 一、概述 ...通过 Java 编程语言和 `com.jacob` 库的强大功能,实现了高效的文件转换任务。对于需要处理大量 Word 文档的用户来说,这是一个非常实用的工具。

    Matlab计算机视觉图像处理工具箱推荐 计算机视觉.pdf

    Matlab是计算机视觉和图像处理领域中常用的开发语言, mặc dù它自带了图像处理和计算机视觉的许多功能,但是术业有专攻,在进行深入的视觉算法研究的时候Matlab的自带功能难免会不够用。因此,我们需要借助一些...

    2021-2022计算机二级等级考试试题及答案No.18479.docx

    SQL 语言主要包括数据定义语言(DDL)、数据操纵语言(DML)和数据控制语言(DCL),不涉及关系规范化。 ### 8. Java 中字符串的操作 - **知识点**:Java 提供了 `String` 和 `StringBuffer` 类来处理字符串。 - *...

    2023年全国7月高等教育自学考试互联网数据库试题部分答案.doc

    2. **SQL 语言**:SQL中的`GRANT`和`REVOKE`语句用于实现数据库的安全性控制,它们分别用于赋予和撤销用户对数据库对象的访问权限。 3. **数据模型**:数据模型的三个要素是数据结构、数据操作和数据完整性约束。...

    JAVA 对word 内容的提取返回String

    我们将通过两种方式来实现这个目标,分别是使用 Java 流读取 Word 内容和使用 Jacob 读取 Word 内容。 使用 Java 流读取 Word 内容 在第一个示例中,我们使用 Java 流来读取 Word 文档的内容。我们首先需要引入...

Global site tag (gtag.js) - Google Analytics