1

I'd like to use lower_bound with the value_type of a Boost MultiIndex Container. So far, I only managed to make this work by explicitly extracting the members:

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <string>

struct name {
    std::string firstname;
    std::string lastname;
    name(const std::string & firstname, const std::string & lastname) :
        firstname(firstname), lastname(lastname) {}
};

typedef boost::multi_index::multi_index_container<
    name,
    boost::multi_index::indexed_by<
        boost::multi_index::ordered_unique<
            boost::multi_index::composite_key<
                name,
                boost::multi_index::member<name, std::string, &name::lastname>,
                boost::multi_index::member<name, std::string, &name::firstname>
            >,
            boost::multi_index::composite_key_compare<
                std::less<std::string>,
                std::less<std::string>
            >
        >
    >
> NameIndex;

int main(void) {
    NameIndex nameindex;
    nameindex.insert(name("Alfred", "Ammer"));
    nameindex.insert(name("Martin", "Mauser"));
    // In my real code, I get this object passed.
    name lookupname("Hans", "Hoffer");

    // Does not compile
    //auto it = nameindex.get<0>().lower_bound(lookupname);

    // compiles, but I have to take explicitly list the members - in the right order
    auto it = nameindex.get<0>().lower_bound(std::make_tuple(lookupname.lastname, lookupname.firstname));
}

How can I avoid extracting the members?

Joaquín M López Muñoz
  • 5,243
  • 1
  • 15
  • 20
W.Mann
  • 893
  • 5
  • 11

2 Answers2

3

Write

auto it = nameindex.get<0>().lower_bound(
    nameindex.get<0>().key_extractor()(lookupname));
Joaquín M López Muñoz
  • 5,243
  • 1
  • 15
  • 20
0

Try the following:

Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <string>

struct name {
    std::string firstname;
    std::string lastname;
    name(const std::string & firstname, const std::string & lastname) :
        firstname(firstname), lastname(lastname) {}
};

struct name_compare:
    boost::multi_index::composite_key_compare<
        std::less<std::string>,
        std::less<std::string>
    >   
{
    using base=boost::multi_index::composite_key_compare<
        std::less<std::string>,
        std::less<std::string>
    >;

    using base::operator();

    template<typename T>
    bool operator()(const T& x,const name& y)const
    {
      return base::operator()(
          x,
          std::make_tuple(std::ref(y.firstname),std::ref(y.lastname)));
    }

    template<typename T>
    bool operator()(const name& x,const T& y)const
    {
      return base::operator()(
          std::make_tuple(std::ref(x.firstname),std::ref(x.lastname)),
          y);
    }
};

typedef boost::multi_index::multi_index_container<
    name,
    boost::multi_index::indexed_by<
        boost::multi_index::ordered_unique<
            boost::multi_index::composite_key<
                name,
                boost::multi_index::member<name, std::string, &name::lastname>,
                boost::multi_index::member<name, std::string, &name::firstname>
            >,
            name_compare
        >
    >
> NameIndex;

int main(void) {
    NameIndex nameindex;
    nameindex.insert(name("Alfred", "Ammer"));
    nameindex.insert(name("Martin", "Mauser"));
    // In my real code, I get this object passed.
    name lookupname("Hans", "Hoffer");

    auto it = nameindex.get<0>().lower_bound(lookupname);

    // this also works, as before

    it = nameindex.get<0>().lower_bound(std::make_tuple(lookupname.lastname, lookupname.firstname));
}
Joaquín M López Muñoz
  • 5,243
  • 1
  • 15
  • 20
  • That does not really solve the problem. Although I can use lower_bound now with `name` objects, I still have to reflect the ordering of the composite key in some helper code. You actually demonstrated that this can be dangerous because you assumed the ordering would be although I defined it as . Is it really impossible to use the ordering that is defined by the multi_index::composite_key? – W.Mann Jul 04 '17 at 17:17
  • 1
    OK, I get what you mean. See my other answer. – Joaquín M López Muñoz Jul 04 '17 at 17:56