Boost logo

Boost Users :

From: Joaquín Mª López Muñoz (joaquin_at_[hidden])
Date: 2008-02-20 13:02:53


Dwight Kelly ha escrito:

> Hello,
>
> I've encountered a problem compiling code that uses boost
> multi_index_container. I'm using both Microsoft Visual Studio 2005 and
> Apple's gcc 4.0.1. Visual Studio was very picky about how I used
> namespaces. I finally got it working with the code below.
>
> The key to success was the 'using namespace boost::multi_index' line. If
> I attempted to prefix the members directly, eg.
>
> typedef typename boost::multi_index::nth_index_const_iterator<0>::type
> left_const_iterator;
>
> or
>
> namespace mi=boost::multi_index;
> typedef typename mi::nth_index_const_iterator<0>::type left_const_iterator;
>
> it would fail to compile.
>
> However, when I attempt to compile the same code on Mac OS X using gcc
> 4.0.1 I get the following errors. Does anyone know why?

[...]

Hello Dwight,

For the sake of reference, let me reproduce the relevant part of your code:

  using namespace boost::multi_index;

  template<class A, class B=String>
  class SimpleBiMap : public multi_index_container<
    pair<A,B>,
    indexed_by<
      ordered_unique<member<pair<A,B>, A, &pair<A,B>::first> >,
      ordered_unique<member<pair<A,B>, B, &pair<A,B>::second> >
> >
  {
  public:
    typedef pair<A,B> mytype;
    typedef typename nth_index_const_iterator<0>::type left_const_iterator;
    typedef typename nth_index_const_iterator<1>::type right_const_iterator;
    ...

First of all, there are two variants of nth_index_const_iterator:

  * a global boost::multi_index::nth_index_const_iterator<MultiIndexContainer,N>
  * a nested MultiIndexContainer::nth_index_const_iterator<N>

where the former accepts two arguments (the container type and the index number)
while the latter, being nested into the container itself, only asks for the index number.
Your code clearly means to use the second variant, but it does so in an incorrect
fashion: you are expecting that nth_index_const_iterator is "found" inside the
base class of SimpleBiMap, much as this *non-template* legal code does:

  struct base
  {
      typedef int type;
  };

  struct derived: public base
  {
      typedef type type2;
  };

Unfortunately, this idiom does not extend to templatized code, even if you qualify
the definition with a "typename" keyword. A little more info on this can be found
at http://www.comeaucomputing.com/techtalk/templates/#whymembernotfound

So, you need to qualify the typedefs as follows:

  typedef multi_index_container<
    mytype,
    indexed_by<
      ordered_unique<member<mytype, A, &mytype::first> >,
      ordered_unique<member<mytype, A, &mytype::second> >
>
> super;
  typedef typename super::template nth_index_const_iterator<0>::type left_const_iterator;
  typedef typename super::template nth_index_const_iterator<1>::type right_const_iterator;

As you see, you have to repeat the full type you are deriving from, which in the
case of long multi_index_container instantiations is a bit annoying. Incidentally, you
were missing some "template" keywords before nth_index_const_iterator, some
compilers are lenient about this though.

As for why your code compiled in VS, I'd say it was sheer luck: the code as you
wrote it is illegal and VS should have complained. Looks like the using directive
leads the compiler into taking the definitions of left_const_iterator and right_const_iterator
as referring to the global variant of nth_index_const_iterator (which they are not)
but on some further stage of the compilation the right variant ends up being chosen.

Hope this helps,

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