Boost logo

Boost Users :

From: JOAQUIN LOPEZ MU?Z (joaquin_at_[hidden])
Date: 2005-12-31 12:27:23


Hello Matt,

----- Mensaje original -----
De: Matt Steele <steelerm_at_[hidden]>
Fecha: Sábado, Diciembre 31, 2005 8:21 am
Asunto: [Boost-users] [multi_index] const_mem_fun with an inherited
memberfunction

> I am trying to use Boost.Multi-index (version 1.33.0) to store a
> set of
> boost::tuples, and it appears that const_mem_fun has some
difficulties
> when the desired member function is inherited from a base class. The
> following typedef
>
> typedef multi_index_container<
> tuple<int>,
> indexed_by< ordered_non_unique< const_mem_fun< tuple<int>,
> const int&,
> &tuple<int>::get<0>
> >
> >
> >
> > my_tuple_container_type;
>
> yields this error (edited for clarity) on my compiler (g++ 4.0.3):
>
> &TupleBaseClass<int>::get' is not a valid template argument for
> type
> 'const int& (tuple<int>::*)()const' because it is of type
> 'const int& (TupleBaseClass<int>::*)const'
> note: standard conversions are not allowed in this context
>
>
> Now the declaration of boost::tuple has something like this:
>
> template <class T>
> class tuple : public TupleBaseClass<T> {
> public:
> typedef typename TupleBaseClass<T> inherited;
> ...
> };
>
> (Also, as far as I can tell, get<0>() is declared and implemented in
> TupleBaseClass, not tuple). The public typedef 'inherited' looked
> promising, so I modified my code as follows:
>
> typedef multi_index_container<
> tuple<int>,
> indexed_by< ordered_non_unique< const_mem_fun<
> tuple<int>::inherited,
> const int&,
> &tuple<int>::get<0>
> >
> >
> >
> > my_tuple_container_type;
>
> and that compiles.
>
> I have a few questions/comments about all this. First of all, is my
> compiler correct to generate the error for the first case?

Unfortunately, it is correct. There are some quirks
about the contravariance rules of pointer to members
in C++. For instance, the following is legal (as expected):

struct A
{
  int x;
};

struct B:A{};

int main()
{
  int B::* p=&B::x;
}

whereas the following is not:

struct A
{
  int x;
};

struct B:A{};

template<int B::*Ptr>
struct foo{};

int main()
{
  // error: argument of type "int A::*" is incompatible with
  // template parameter of type "int B::*"
  foo<&B::x> f;
}

To me, this is a defect in the standard, but there might
be a reason for this behavior. I'll go ask in comp.std.c++.

> Secondly, is
> the above workaround satisfactory? My opinion is that it's a little
> ungainly; it appears to me that boost::tuple is a derived type for
> implementation reasons, and I'd rather not have to know about that
> fact.

It is unsatisfactory for two reasons:

1. As you say, having to expose an implementation artifact is
ugly.
2. I think that the code won't work as expected: const_mem_fun
has some overloads of operator() in order to support
chained pointers (http://tinyurl.com/9cd2v) that will hide
the implicit conversion from const tuple<int>& to
const tuple<int>::inherited&. Could you please try to insert
some element in my_tuple_container_type? My hunch is that
you'll get a compiler error about tuple<int> not having
operator*. Please report back.

As for issue #2, I've corrected the problem (for SFINAE-capable
compilers) for the next Boost 1.34 release. Even so, issue #1
remains. My suggestion is that you simply provide a user-defined
key extractor like this (uncompiled, beware typos):

template<typename Tuple,int N>
struct tuple_member_extractor
{
  typedef typename
    boost::tuples::element<N,Tuple>::type result_type;

  const result_type& operator()(const Tuple& t)const
  {
    return boost::tuples::get<N>(t);
  }
};

Hope this helps; I'd appreciate if you reported on the
success/failure of this approach.

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