2013-07-18 24 views
6

Potrzebuję utworzyć związek, ale 2 członków związku będzie miało ten sam typ, dlatego potrzebuję sposobu, aby je zidentyfikować. Na przykład w OCaml:Oznaczone związki (aka wariant) w C++ tego samego typu wiele razy

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

Boost.Variant wydaje się nie wspierać tego przypadku, czy istnieje znana biblioteka, która obsługuje to?

+3

Dlaczego dwa tego samego typu? Tylko jeden członek związku może być użyty w tym samym czasie. – hmjd

+2

Wiem, ale są przypadki, kiedy chciałbyś rozproszyć członka, nawet jeśli mają ten sam podstawowy typ. Mały przykład to typ Expr z 2 elementami IntConst int i IntMutable of int. – maattdd

+2

Ale gdzieś musi być gdzieś inna flaga (zawierająca 'struct' lub' class'), która wskazuje, który członek związku jest _aktywny? To może być użyte w celu zapewnienia dodatkowego wymaganego znaczenia. – hmjd

Odpowiedz

5

Jeśli chcesz to zrobić, myślę, że najlepszym rozwiązaniem jest, aby owinąć te same, ale różny typy w struktury, które następnie pozwala wariant doładowania odwiedzić właściwy jeden:

struct Speed 
{ 
    float val_; 
}; 

struct Darkness 
{ 
    float val_; 
}; 

Ty może być w stanie użyć BOOST_STRONG_TYPEDEF, aby zrobić to automatycznie, ale nie jestem pewien, czy jest gwarantowane generowanie typów legalnych do użycia w związku (chociaż prawdopodobnie byłoby w porządku w wariancie).

2

C++ kod tutaj:

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

to prawdziwy rekord z wariantami, że może zawierać zduplikowane typy. Jedną fajną cechą jest to, że znaczniki mogą być wyliczeniami; w związku z tym znaczniki mogą mieć znaczące nazwy.

Niestety, czas kompilacji jest dość zły, jak sądzę, ponieważ implementacja wykorzystuje dziedziczne dziedziczenie. OTOH, może kompilatory w końcu wymyślą sposób, aby zmniejszyć koszt czasu kompilacji.

OTOH, jeśli chcesz, aby trzymać z boost :: wariantu, można owinąć typy, jak sugeruje Mark B. Jednak zamiast opisowych nazw klas Mark B, , które wymagają pewnej myśli, można użyć fusion::pair<mpl::int_<tag>,T_tag> gdzie T_tag jest tag-th elementem w źródle fusion::vector. IOW:

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

Jak docs fuzyjnych:

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

powiedzieć, fusion::pair przydziela tylko przestrzeń dla 2nd szablonu argumentu; w związku z tym nie powinno to zająć więcej miejsca niż boost::variant<T1,T2,...,Tn>.

HTH.

-regards, Larry

1

Nie można w tej chwili, ale C++17's implementation of std::variant szczęście pozwala go:

Wariant wolno posiadać taki sam typ więcej niż raz, i trzymać inaczej cv wykwalifikowany wersje tego samego typu.

odróżnieniu od wersji Boost, można uzyskać przez wartości wskaźnika, coś takiego (nie testowane):

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

Powiązane problemy