Boost logo

Boost Users :

From: Joaquín Mª López Muñoz (joaquin_at_[hidden])
Date: 2007-03-14 13:08:03


Hello Boris,

Boris ha escrito:

> As I find myself replacing all kind of C++ standard containers with
> multi_index_container (a really very useful container) I've been defining
> key extractors quite a lot and wonder if there is any shortcut like using
> lambda expressions or function objects. Here's some pseudo-code to
> explain what I mean:
>
> struct foo
> {
> std::string s;
> foo(std::string s) : s(s) { }
> };
>
> typedef multi_index_container<
> foo,
> indexed_by<
> hashed_unique<
> boost::bind<std::size_t, &std::string::size, member<foo, std::string,
> &foo::s> >
> >
> >
> > mi_t;
>
> The idea is to call another function on the object which is returned by
> the key extractor member. Here in this example the multi_index_container
> would only store strings with a unique size. However I'm lost how to
> define the key extractor. The difficulty is probably that I normally don't
> need to specify types when I use boost::bind or lambda expressions. Now I
> need to figure out how to use them with multi_index_container - is there
> any trick or I better go on defining key extractors?

Well, you can approach to what you want if your compiler provides a
typeof() facility. If this is the case, a first attempt to define your key extractor
based on boost::bind could be like this:

  typedef multi_index_container<
    foo,
    indexed_by<
      hashed_unique<
        typeof(boost::bind(&std::string::size,boost::bind(&foo::s,_1)))
>
>
> mi_t;

which unfortunately does *not* work because of the following: the type
typeof(expr) (with "expr" standing for the boost::bind expression above) is
not default constructible, which the usual usage of key extractors assumes,
i.e., the following does not compile:

  typeof(expr) x;

But the following does actually work:

  typeof(expr) x(expr);

which can be leveraged to define our boost::bind-based extractor, albeit
by resorting to an out-of-typedef definition:

  #define DEFINE_BIND_TYPE(name,expr) \
  typedef boost::remove_reference< \
    boost::remove_cv<typeof(expr)>::type>::type name##_expr_type; \
                                                                  \
  struct name:name##_expr_type \
  { \
    name():name##_expr_type(expr){} \
  };

  DEFINE_BIND_TYPE(
    extractor,
    boost::bind(&std::string::size,boost::bind(&foo::s,_1)))

  typedef multi_index_container<
    foo,
    indexed_by<
      hashed_unique<extractor>
>
> mi_t;

Whether this is more convenient than writing your own key extractors is
a debatable issue... One final warning: this trick relies on an undocumented
feature of boost::bind, namely that the function objects produced by this
lib own a result_type nested typedef, as required by the key extractor
concept --otherwise the classes defined by DEFINE_BIND_TYPE
wouldn't be conformant key extractors. So, if you want to stand on the
documented side you couldn't use this. Also, this is one reason why
thes idiom does not extend to boost::lambda expressions.

The attached snippet compiles and works with GCC 3.2.

HTH,

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo




Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net