
Hello Matt, ----- Mensaje original ----- De: Matt Steele <steelerm@netlab.uky.edu> 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