2012-02-05 21 views
5

Dアプリケーションの設計に問題があります。たぶん私のアプローチは完全に間違っているので、私はここであなたを救い出す。完全な書き換えを含むすべての提案は、大歓迎です。D型構造の構造体を共通型として扱う

私はいくつかのテンプレートの種類があります。

enum Type : byte { Message='!', Integer='@' } 

struct Token (T) { 
    Type type; 
    T value; 
} 

alias Token!string MessageToken; 
alias Token!long IntegerToken; 

をそして私は一般的に、これらのタイプを処理する必要があります。

AnyToken genToken(bool cond) { 
    if (cond) 
    return MessageToken(Type.Message, "nighly builds"); 
    else 
     return IntegerToken(Type.Integer, -42); 
} 

AnyToken a = genToken(true); 
AnyToken b = genToken(false); 

どのように私はこの効果を達成できますか? 編集: OOPの代替も歓迎します。

答えて

6

私がタグ付けされた労働組合を使用していると思います私自身は

struct Token{ 
    Type type; 
    union{ 
     string str; 
     long integer; 
    } 
    @property string strMessage()in{assert(type==Type.Message)}body{ 
     return str; 
    } 
    @property void strMessage(string s){ 
     type=Type.Message; 
     str=s; 
    } 
    @property long intMessage()in{assert(type==Type.Integer)}body{ 
     return integer; 
    } 
    @property void intMessage(long l){ 
     type=Type.Integer; 
     integer=l; 
    } 
} 

ノートいくつかの余分な関数は継承のように見えるので、構造体の関数の外で多くの型フィールドを調べる必要はありません。

+0

どのように関数を追加できますか?継承のように見えますか?より少ない検査が良いでしょう。私は引数から型を推論する方法が好きです、ここでうまくいきます。 –

+1

関数の中で 'final switch(type){case Type.Integer:... case Type.Message:...}'関数を処理できます。私はそれらのチェックの大部分が構造体の定義の中に集中することを意味していましたので、タイプを追加したいときにそれらをすべて削除する必要はありません –

+0

ありがとう、今私は 'final switch'を使用していますそれのための。 –

4

std.variantを使用できます。

私は別の方法を想像することはできません。最終的には完全に別のタイプです。そこには、静的にはその差が(コンパイル時)ませんが、それはかなりあなたが追加することができます継承

せずに行うことができますで最高だと

+1

自分のタグ付き共用体を構築するのではなく、 'std.variant'を使用することに利点がありますか? –

2

本当に元の構造体を保持する必要があれば、ポインタそれに応じて構造体に渡してディスパッチします。

+0

いいえ、私は構造体を保持する必要はありません。保護された共用体をラップするクラス階層はどうですか?少数またはゼロのコピーを持つ小さなトークンが数多くあります。 –