Boost logo

Boost :

From: David Gruener (David.Gruener_at_[hidden])
Date: 2005-02-16 14:55:53


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:



#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
  typedef typename KeyExtractor1::result_type result_type;

    const KeyExtractor1& key1_=KeyExtractor1(),
    const KeyExtractor2& key2_=KeyExtractor2()):

  template<typename Arg>
  result_type operator()(Arg& arg)const
    return key1(key2(arg));

  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;

> 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
  #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?


Boost list run by bdawes at, gregod at, cpdaniel at, john at