ziv ziv - 1 month ago 13
C++ Question

Compiling boost::multi_index with std::shared_ptr with GCC

This code compiles with visual studio 2015.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/key_extractors.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/random_access_index.hpp>

#include <memory>

namespace bmi = boost::multi_index;

class Link {};

typedef std::shared_ptr<Link> Link_Ptr;


struct ByRnd {};
struct ByPtr {};

typedef boost::multi_index_container<Link_Ptr,
bmi::indexed_by<
bmi::random_access<
bmi::tag<ByRnd>
>,
bmi::hashed_unique<
bmi::tag<ByPtr>,
bmi::const_mem_fun<Link_Ptr, Link*, &Link_Ptr::get>
>
>
> Store;
Store store;

int main() {}


However, on Ubuntu I am using GCC 6.2 and boost 1.62. And I get the following error:

error:
could not convert template argument ‘&std::__shared_ptr<Link, (__gnu_cxx::_Lock_policy)2u>::get’ to ‘Link* (std::shared_ptr<Link>::*)() const’
bmi::const_mem_fun<Link_Ptr, Link*, &Link_Ptr::get>


and clang 3.8:

error:
non-type template argument of type 'Link *(std::__shared_ptr<Link, __gnu_cxx::_Lock_policy::_S_atomic>::*)() const noexcept' cannot be converted to a value of type
'Link *(std::shared_ptr<Link>::*)() const'
bmi::const_mem_fun<Link_Ptr, Link*, &Link_Ptr::get>


If I use
boost::shared_ptr
instead, GCC compiles fine too.

Answer

Looks like a QoI issue with GNU libstdc++. – sehe 1 hour ago

What does that mean? Is there anything I can do about it? – ziv 15 secs ago

It means "Quality of Implementation", meaning an unspecified detail in the library implementation is making life harder than you want it be (likely due to namespace versioning, but I'm guessing that a bit).

What can I do?

It looks like you just want to use the pointer identity, which is easier:

bmi::hashed_unique<bmi::tag<struct ByPtr>, bmi::identity<Link_Ptr> >

Live On Coliru

#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/key_extractors.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index_container.hpp>

#include <memory>
#include <iostream>
#include <cassert>

namespace bmi = boost::multi_index;

class Link {};

typedef std::shared_ptr<Link> Link_Ptr;

typedef boost::multi_index_container<
    Link_Ptr,
    bmi::indexed_by<bmi::random_access<bmi::tag<struct ByRnd> >,
                    bmi::hashed_unique<bmi::tag<struct ByPtr>, bmi::identity<Link_Ptr> > > >
    Store;
Store store;

int main() {
    auto a = std::make_shared<Link>();
    auto b = a; // same

    auto& idx = store.get<ByPtr>();
    idx.insert(a);
    auto res = idx.insert(b);
    assert(!res.second);

    std::cout << "effective number of links: " << store.size() << "\n";
}

Alternatively

You could use bmi::global_fun:

template <typename T> static T *get_ptr(std::shared_ptr<T> const &p) 
{ return p.get(); }

Live On Coliru

#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/key_extractors.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>

#include <cassert>
#include <iostream>
#include <memory>

namespace bmi = boost::multi_index;

class Link {};

typedef std::shared_ptr<Link> Link_Ptr;

template <typename T> static T *get_ptr(std::shared_ptr<T> const &p) { return p.get(); }

typedef boost::multi_index_container<
    Link_Ptr, bmi::indexed_by<bmi::random_access<bmi::tag<struct ByRnd> >,
                              bmi::hashed_unique<bmi::tag<struct ByPtr>,
                                                 bmi::global_fun<Link_Ptr const &, Link *, &get_ptr<Link> > > > >
    Store;
Store store;

int main() {
    auto a = std::make_shared<Link>();
    auto b = a; // same

    auto &idx = store.get<ByPtr>();
    idx.insert(a);
    auto res = idx.insert(b);
    assert(!res.second);

    std::cout << "effective number of links: " << store.size() << "\n";
}
Comments