1

I need to overload the [] operator for boost::multi_index_container. It would look like something like this :

template<typename T>
using my_set = boost::multi_index_container<
    T,
    boost::multi_index::indexed_by<
        boost::multi_index::sequenced<>,
        boost::multi_index::ordered_unique<boost::multi_index::identity<T>>
    >
>;

template<typename T>
T operator[](const my_set &s, const size_t &t){
    auto it=s.get<0>.begin();
    advance(it, t);
    return *it;
}

I tried but I get this error :

error: ‘T operator[](boost::multi_index::multi_index_container<T, boost::multi_index::indexed_by<boost::multi_index::sequenced<>, boost::multi_index::ordered_unique<boost::multi_index::identity<Value> > > >&, int&)’ must be a nonstatic member function
 \> &s, int &t){

Is there any way I can do this ?

I want to do this because I had a vector and I need to insert unique elements in it. I used find to know if the element was already in my vector then inserted it if it wasn't. But the linear complexity of find on a vector bothered me, I thought of using a set but I want to keep the elements in the insertion order.

Using a multi_index_container allows me to keep the insertion index with s.get<0> but will also allow me to have unique elements in it

I hope everything's clear.

Joaquín M López Muñoz
  • 5,243
  • 1
  • 15
  • 20
Armure
  • 25
  • 5

1 Answers1

2

On first read I thought you wanted to have something like std::map::operator[], but that's a bad idea, see below.

On second read I noticed that you ONLY want random-access to the sequenced index. sequenced has list-like semantics.

You're in luck, random-access indexes already exist! Just use it instead:

Live On Compiler Explorer

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <fmt/ranges.h>

namespace bmi = boost::multi_index;

template <typename T>
using my_set = bmi::multi_index_container<
    T,
    bmi::indexed_by<bmi::random_access<>,
                    bmi::ordered_unique<bmi::identity<T>>>>;

int main() {
    my_set<int> s{1, 7, 7, 8, -4, 22, 1, 5, 4};

    fmt::print("Original: {}\n", s);
    fmt::print("Same:     {}\n", s.get<0>());
    fmt::print("Ordered:  {}\n", s.get<1>());
    fmt::print("Element 2: {}\n", s[2]);
}

Prints:

Original: [1, 7, 8, -4, 22, 5, 4]
Same:     [1, 7, 8, -4, 22, 5, 4]
Ordered:  {-4, 1, 4, 5, 7, 8, 22}
Element 2: 8

OLD answer: Why Associative operator[] is a bad idea

"I need to overload the [] operator for boost::multi_index_container" - actually, you don't. You may want to.

Here's why it's not a good idea.

  • operator[] on standard associative containers (like std::map) is not const. It will insert entries if the key isn't found, and will also return a mutable reference to the value.

  • operator[] doesn't exist on non-unique standard library containers either! E.g. std::multimap does not have operator[] - think about it: which element should be returned?

Boost MultiIndex shares the second reason for not providing these operations. However, regardless of that, all values are always const in a multi-index container.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • An advanced application is projecting iterators between indices: https://godbolt.org/z/8KdW1od81 – sehe Mar 30 '22 at 21:58
  • 1
    Gah. So much time wasted. Turns our I [already answered](https://stackoverflow.com/a/43194272/85371) a very similar question in 2017. There's another answer there from the library developer, so do look over there too! – sehe Mar 30 '22 at 22:05