2013-07-18 11 views
6

Ich muss eine Union erstellen, aber 2 Mitglieder der Union würden den gleichen Typ haben, also brauche ich eine Möglichkeit, sie zu identifizieren. Zum Beispiel in OCaml:Tagged Unions (aka Variante) in C++ mit dem gleichen Typ mehrmals

type A = 
    | B of int 
    | C of float 
    | D of float 

Boost.Variant diesen Fall nicht zu unterstützen scheint, gibt es eine bekannte Bibliothek, die das unterstützt?

+3

Warum zwei gleiche "Typ"? Es kann immer nur ein Mitglied einer Vereinigung verwendet werden. – hmjd

+2

Ich weiß, aber es gibt Fälle, wenn Sie disdressing zu Mitglied möchten, selbst wenn sie den gleichen zugrunde liegenden Typ haben. Ein kleines Beispiel wäre ein Expr-Typ mit 2 Mitgliedern IntConst von int und IntMutable von int. – maattdd

+2

Aber es muss irgendwo eine andere Flagge geben (mit 'struct' oder' class'), die angibt, welches Mitglied der Union _active_ ist? Dies könnte verwendet werden, um die zusätzliche erforderliche Bedeutung bereitzustellen. – hmjd

Antwort

5

Wenn Sie dies tun wollen, ich denke, die beste Wahl ist die gleiche, aber-verschieden-Typen in einer Struktur zu wickeln, die dann die Boost-Variante die richtige ist besuchen können:

struct Speed 
{ 
    float val_; 
}; 

struct Darkness 
{ 
    float val_; 
}; 

Sie könnte in der Lage sein, BOOST_STRONG_TYPEDEF zu verwenden, um dies automatisch zu tun, aber ich bin mir nicht sicher, es ist garantiert, Typen für die Verwendung in einer Union zu generieren (obwohl es wahrscheinlich in einer Variante in Ordnung wäre).

2

Der C++ Code hier:

http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/composite_storage/pack/container_one_of_maybe.hpp

ist wirklich ein getaggt Union, dass sie doppelte Typen enthalten. Ein nettes Feature ist die Tags Enumerationen; Daher können die Tags sinnvolle Namen haben.

Leider sind die Kompilierzeitkosten ziemlich schlecht, denke ich, weil die Implementierung rekursive Vererbung verwendet. OTOH, vielleicht Compiler werden schließlich einen Weg herauszufinden, um die Kompilierzeit Kosten zu verringern.

OTOH, wenn Sie mit boost :: variant bleiben möchten, können Sie die Typen als Mark B vorschlagen. Anstelle der beschreibenden Klassennamen von Mark B, , die einige Überlegungen erfordern, könnten Sie jedoch fusion::pair<mpl::int_<tag>,T_tag> verwenden, wobei T_tag das Tag-te Element in der Quelle fusion::vector ist. IOW:

variant 
< fusion::pair<mpl::int_<1>,T1> 
, fusion::pair<mpl::int_<2>,T2> 
... 
, fusion::pair<mpl::int_<n>,Tn> 
> 

Da die Fusion docs:

http://www.boost.org/doc/libs/1_55_0/libs/fusion/doc/html/fusion/support/pair.html

sagen, fusion::pair nur Platz für das Argument 2. Vorlage zuordnet; Daher sollte nicht mehr Platz als boost::variant<T1,T2,...,Tn> nehmen.

HTH.

-regards, Larry

1

Sie können nicht im Moment, aber C++17's implementation of std::variant zum Glück erlaubt es:

Eine Variante erlaubt die gleiche Art mehr als einmal zu halten, und anders cv-qualifiziert zu halten Versionen desselben Typs.

Anders als bei der Boost-Version, können Sie Werte von Index bekommen, so etwas wie diese (nicht getestet):

// Construct a variant with the second value set. 
variant<string, string, string> s(std::in_place_index<1>, "Hello"); 
// Get the second value. 
string first = std::get<1>(s); 

Michael Park a C++14 implementation of C++17's std::variant geschrieben hat.