$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [Boost-users] [MultiIndex] Visual C++ 10 issue
From: joaquin_at_[hidden]
Date: 2010-05-11 02:23:35
Jeremiah Willcock escribió:
> On Mon, 10 May 2010, Richard Webb wrote:
>
>   
>> Sounds like the same problem as 
>> https://svn.boost.org/trac/boost/ticket/3594
>>     
>
> It seems like it is.  Is the workaround that complicated, though?  Is 
> there a way to get some of that factored out to reuse in other Boost 
> libraries?  Would putting an explicit cast to ... std::pair::* in the 
> template argument work instead?
>   
Hi Jeremiah,
The problem is not a bug with VC++ 10, but a collateral effect of the 
way std::pair
is implemented in the stdlib provided for this compiler --namely, by 
deriving from an
implementation-specific _Pair_base class where the members are actually 
defined.
This reduced test case can help explain the problem:
  struct base{int x;};
  struct derived:base{};
  template<
    class Class,
    typename Type,
    Type Class::*PtrToMember
  >
  struct member{};
  typedef member<derived,int,&derived::x> member_t;
The last typedef fails with "argument of type 'int base::*' is 
incompatible with template
parameter of type 'int derived::*'" or something to that effect because 
x is defined in
base rather than derived, so the type of &derived::x is actually int 
base::*, for which
the standard conversion to int derived::* does not apply in the context 
of template
argument matching, see 14.3.2 [temp.arg.nontype] paragraph 5:
  "[...] for a nontype template-parameter of type pointer to object, 
qualification
  conversions (4.4) and the array-to-pointer conversion (4.2) are 
applied. [Note:
  In particular, neither the null pointer conversion (4.10) nor the 
derived-to-base
  conversion (4.10) are applied. [...] ]"
I don't really know the rationale behind the paragraph above, but this 
is the way
things are.
The workaround applied at https://svn.boost.org/trac/boost/ticket/3594 
works,
but it's probably overkill (and uses the objectionable member_offset, 
which is
really meant to be used as a last resort for legacy compilers). A nicer 
workaround
consists in providing a user-defined key extractor:
  template<typename First,typename Second>
  class pair_first_extractor
  {
    typedef std::pair<First,Second> value_type;
  public:
    typedef First result_type;
    const result_type& operator()(const value_type& x)const
    {
      return x.first;
    }
    result_type& operator()(value_type& x)const
    {
      return x.first;
    }
  };
  typedef multi_index::multi_index_container<
   std::pair<key_type, value_type>,
   multi_index::indexed_by<
     multi_index::sequenced<>,
     multi_index::hashed_unique<
       pair_first_extractor<key_type, value_type>
     >
   >
  > ghost_cells_type;
HTH,
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo