
Hello, i just started using the boost::multi_index_container and ran into some trouble. I'm using boost version 1.32. Well, i tried a slightly modified version of Example 6 ("complex searches and foreign keys"). This is the code: -------------------------------------------------------------------------- #define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING #define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE #include <boost/multi_index_container.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/mem_fun.hpp> #include <string> using namespace std; using namespace boost; using namespace boost::multi_index; template<class KeyExtractor1,class KeyExtractor2> struct key_from_key { public: typedef typename KeyExtractor1::result_type result_type; key_from_key( const KeyExtractor1& key1_=KeyExtractor1(), const KeyExtractor2& key2_=KeyExtractor2()): key1(key1_),key2(key2_) {} template<typename Arg> result_type operator()(Arg& arg)const { return key1(key2(arg)); } private: KeyExtractor1 key1; KeyExtractor2 key2; }; struct person { string get_name() const { return "GM"; } // XXX }; struct car_manufacturer : public person // XXX { }; struct car_model { string model; car_manufacturer* manufacturer; int price; }; multi_index_container< car_model, indexed_by< ordered_unique< key_from_key< const_mem_fun<person,std::string,&person::get_name>, member<car_model,car_manufacturer*,&car_model::manufacturer> > >
mic;
-------------------------------------------------------------------------- As one might see, the change i made is that the key get_name() of the car_manufacturer now comes from a base class called person. However, this code wont compile because the compiler argues that there is no '*' operator for car_manufactuerer. I found out that the problem is the handling with the so called chained pointers in the mem_fun structs. template<typename ChainedPtr> Type operator()(const ChainedPtr& x)const // [1] { return operator()(*x); } Type operator()(const Class& x)const // [2] { return (x.*PtrToMemberFunction)(); } In the example the compiler calls [1] for car_manufacturer*, which seems right. After that, it can chose (among other methods) between [1] and [2] (Class = person) with argument type car_manufacturer and choses the better matching [1] with the followed error. However, maybe things could be done better here. The mem_fun structs could be smart enogh to deal with classes derived from template argument Class. That means [2] should be called in the case of operator() with a "Class"-derived argument. I dont know much about metaprogramming, but the following diff for const_mem_fun (as an example) of file mem_fun.hpp seems to work with a compiler supporting full template specialisation at class scope. Unfortunately gcc up to 3.4 doesn't seem to support this, while icc 8.0 does. I'm pretty sure there is a better sollution than mine, assumed that a "problem" even exists, which is my question to you. :] ------------------------------------------------------------------------------- *************** *** 12,17 **** --- 12,18 ---- #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ #include <boost/mpl/if.hpp> #include <boost/type_traits/remove_reference.hpp> + #include <boost/type_traits/is_base_and_derived.hpp> namespace boost{ *************** *** 45,54 **** { typedef typename remove_reference<Type>::type result_type; ! template<typename ChainedPtr> ! Type operator()(const ChainedPtr& x)const { ! return operator()(*x); } Type operator()(const Class& x)const --- 46,58 ---- { typedef typename remove_reference<Type>::type result_type; ! template<typename MaybeChainedPtr> ! Type operator()(const MaybeChainedPtr& x)const { ! return dispatch_cptr< typename mpl::if_< ! is_base_and_derived<Class, MaybeChainedPtr>, ! Class, ! MaybeChainedPtr>::type > (x); } Type operator()(const Class& x)const *************** *** 65,70 **** --- 69,87 ---- { return operator()(x.get()); } + + private: + template<typename MaybeChainedPtr> + Type dispatch_cptr(const MaybeChainedPtr& x)const + { + return operator()(*x); + } + + template<> + Type dispatch_cptr<Class>(const Class& x)const + { + return operator()(x); + } }; ------------------------------------------------------------------------------ Would some type handling like this make sense? If not, whats the best way to use dervied member function of a (pointer)member of the container type as key? If yes, are there similar issues in other extractors like member extractor? --David