2013-07-18 12 views
6

ho bisogno di creare un'unione, ma 2 membri dell'Unione avrebbero lo stesso tipo, quindi ho bisogno di un modo per identificarli. Per esempio in OCaml:sindacati targhetta (aka variante) in C++ con lo stesso tipo più volte

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

Boost.Variant non sembra per sostenere questo caso, c'è una libreria noto che sostiene che?

+3

Perché due dello stesso 'tipo'? Solo un membro di un sindacato può essere utilizzato in qualsiasi momento. – hmjd

+2

Lo so, ma ci sono casi in cui vorresti distrarre i membri anche se hanno lo stesso tipo di sottotitoli. Un piccolo esempio potrebbe essere un tipo Expr con 2 membri IntConst di int e IntMutable di int. – maattdd

+2

Ma ci deve essere qualche altro flag da qualche parte (contenente 'struct' o' class') che indica quale membro del sindacato è _active_? Questo potrebbe essere usato per fornire il significato aggiuntivo richiesto. – hmjd

risposta

5

Se si vuole fare questo, credo che la soluzione migliore è quella di avvolgere gli stessi, ma-diversi tipi in una struct che poi lascia la variante spinta visitare quello giusto:

struct Speed 
{ 
    float val_; 
}; 

struct Darkness 
{ 
    float val_; 
}; 

È potrebbe essere in grado di utilizzare BOOST_STRONG_TYPEDEF per farlo automaticamente, ma io non sono sicuro che sia garantito a generare forme giuridiche per l'uso in un sindacato (anche se probabilmente sarebbe bene in una variante).

2

Il codice C++ qui:

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

è veramente un sindacato etichettato in quanto può contenere tipi di duplicati. Una bella caratteristica è che i tag possono essere enumerazioni; di conseguenza, i tag possono avere nomi significativi.

Sfortunatamente, il costo del tempo di compilazione è piuttosto negativo, suppongo, perché l'implementazione utilizza l'ereditarietà ricorsiva. OTOH, forse i compilatori alla fine troveranno un modo per ridurre il costo del tempo di compilazione.

OTOH, se si desidera attenersi a boost :: variant, è possibile includere i tipi, come suggerito da Mark B. Tuttavia, al posto dei nomi descrittivi delle classi di Mark B, che richiedono qualche riflessione, è possibile utilizzare fusion::pair<mpl::int_<tag>,T_tag> dove è l'elemento tag-th nell'origine fusion::vector. IOW:

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

Come la documentazione di fusione:

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

dicono, fusion::pair assegna spazio solo per l'argomento secondo modello; di conseguenza, questo non deve prendere alcuna stanza più di boost::variant<T1,T2,...,Tn>.

HTH.

-regards, Larry

1

Non è possibile al momento, ma C++17's implementation of std::variant fortunatamente lo permette:

Una variante è permesso di tenere lo stesso tipo più di una volta, e di tenere in modo diverso cv-qualificato versioni dello stesso tipo.

differenza con la versione spinta, è possibile ottenere valori di indice, qualcosa di simile (non testato):

// 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 ha scritto a C++14 implementation of C++17's std::variant.

Problemi correlati