2009-10-27 22 views
6

Jeśli mam obiektu takiego:Zwiększ pojemnik multi-indeksu z indeksu na podstawie wartości zagnieżdżonych

struct Bar { 
    std::string const& property(); 
}; 

mogę utworzyć kontener multi-index na to tak:

struct tag_prop {}; 
typedef boost::multi_index_container< 
    Bar, 
    boost::multi_index::indexed_by< 
     boost::multi_index::ordered_non_unique< 
      boost::multi_index::tag<tag_prop>, 
      boost::multi_index::const_mem_fun< 
       Bar, const std::string&, &Bar::property 
      > 
     > 
    > 
    , ... other indexes 
> BarContainer; 

Ale jeśli mam klasy jak poniżej:

struct Foo { 
    Bar const& bar(); 
}; 

Jak mogę zbudować indeks na .bar().property() do pojemnika Foo obiektów?

Normalnie chciałbym zagnieżdżać połączenia do boost::bind, ale nie mogę dowiedzieć się, jak sprawić, aby działało w kontekście kontenera wielu indeksów.

Odpowiedz

5

Uważam, że trzeba utworzyć obiekt predykatu, który pobiera dwa wystąpienia Foo, a jego operator() może wywoływać Foo :: bar() w obu instancjach.

Coś

struct MyPredicate 
{ 

    bool operator() (const Foo& obj1, const Foo& obj2) const 
    { 
     // fill in here 
    } 
}; 

a następnie użyć

... 
boost::multi_index::ordered_unique<boost::multi_index::tag<tag_prop>, 
    boost::multi_index::identity<Foo>, MyPredicate>, 
... 

Wyjazd MultiIndex Ordered indices reference

+0

doskonały, dziękuję. –

1

Aż Lubię użyciu lambdy zrobić prostych rzeczy, to może szybko przerodzić :)

W twoim przypadku, ponieważ jest to nieco bardziej skomplikowane, chciałbym albo na darmowej funkcji, albo na komparatorze predykatów. .

Predykat ma tę zaletę, definiowanie typów jaśniej tak to zwykle łatwiejsze do rzeczywiście przynieść go w

Ponadto, ze względu na czytelność jest, zwykle typedef moje indeksy, co daje:

namespace mi = boost::multi_index; 

struct FooComparator 
{ 
    bool operator()(Foo const& lhs, Foo const& rhs) const 
    { 
    return lhs.bar().property() < rhs.bar().property(); 
    } 
}; 

typedef mi::ordered_unique < 
      mi::tag<tag_prop>, 
      mi::identity<Foo>, 
      FooComparator 
     > foo_bar_index_t; 

typedef boost::multi_index_container < 
      Foo, 
      mi::indexed_by < 
      foo_bar_index_t, 
      // ... other indexes 
      > 
     > foo_container_t; 

Podejście oparte na predykacie wymaga większej ilości kodu standardowego, ale pozwala na ładne oddzielenie logiki porównania od definicji indeksu, która sama jest oddzielona od definicji kontenera.

Przejrzysta separacja ułatwia przeglądanie struktury na pierwszy rzut oka.

+0

Uzgodnione. Zazwyczaj używam również aliasów typedefs i namespace, ale ten trywialny przykład wydawał się zbyt skomplikowany, więc zwinąłem je do pojedynczej deklaracji. –

6

Zamiast w komparator zdefiniowany przez użytkownika, można napisać zdefiniowany przez użytkownika kluczowy wyciąg:

 
struct FooBarPropertyExtractor 
{ 
    typedef std::string result_type; 
    const result_type& oeprator()(const Foo& f) 
    { 
    return f.bar().property(); 
    } 
}; 

... 

typedef boost::multi_index_container< 
     Bar, 
     boost::multi_index::indexed_by< 
       boost::multi_index::ordered_non_unique< 
         boost::multi_index::tag<tag_prop>, 
         FooBarPropertyExtractor 
       > 
     > 
     , ... other indexes 
> FooContainer; 

Zobacz Advanced features of Boost.MultiIndex key extractors

Powiązane problemy