[multiindex] [bind] Conversion loses qualifiers
Hello all, First of all, thanks for a wonderful library, it is a pleasure to work with... However I ran into some problems and I can not find the answers either on the Internet nor on this mailing list. The problem at hand concerns the multiindex container and bind. I have a class with the following member: class Statistics { public: void addStats ( double val, int tick ); } and a container: typedef multi_index_container< Statistics, indexed_by <ordered_unique<identity<Statistics> >, ordered_non_unique< member<Statistics,double,&Statistics::gamma> > >
StatisticsMap;
StatisticsMap m_statistic; indexed by : typedef StatisticsMap::nth_index<1>::type StatisticsByResponse; somewhere in code i try to do this : std::pair<StatisticsMap::iterator,bool> result = m_statistic.insert( Statistics( response, value, tick ) ); StatisticsByResponse& idxResponse = m_statistic.get<1>(); StatisticsByResponse::iterator it = m_statistic.project<1>(result.first ); the problem comes when I try to update the statistics by using : for_each( it , idxResponse.end() , boost::bind( &Statistics::addStats, ::_1, val, tick ) ); " ... \boost\boost\bind\mem_fn_template.hpp(260) : error C2440: 'argument' : cannot convert from 'const boost::multi_index::detail::index_node_base<Value>::value_type *' to 'Statistics *const ' with [ Value=Statistics ] Conversion loses qualifiers boost\boost\bind.hpp(347) : see reference to function template instantiation 'R boost::_mfi::mf2<R,T,A1,A2>::operator ()<Statistics>(const U &,A1,A2) const' being compiled with [ R=void, T=Statistics, A1=double, A2=int, U=boost::multi_index::detail::index_node_base<Statistics>::value_type ] .... " I see the problem is that compiler tries to convert Statistics* into Statistics* const, but I do not know how to fix it .. -- Nebojsa Simic
Nebojsa Simic wrote:
Hello all,
First of all, thanks for a wonderful library, it is a pleasure to work with...
However I ran into some problems and I can not find the answers either on the Internet nor on this mailing list. The problem at hand concerns the multiindex container and bind.
I have a class with the following member:
class Statistics { public: void addStats ( double val, int tick ); }
and a container:
typedef multi_index_container< Statistics, indexed_by <ordered_unique<identity<Statistics> >, ordered_non_unique< member<Statistics,double,&Statistics::gamma> > >
StatisticsMap;
StatisticsMap m_statistic;
indexed by :
typedef StatisticsMap::nth_index<1>::type StatisticsByResponse;
somewhere in code i try to do this :
std::pair<StatisticsMap::iterator,bool> result = m_statistic.insert( Statistics( response, value, tick ) );
StatisticsByResponse& idxResponse = m_statistic.get<1>(); StatisticsByResponse::iterator it = m_statistic.project<1>(result.first );
the problem comes when I try to update the statistics by using :
for_each( it , idxResponse.end() , boost::bind( &Statistics::addStats, ::_1, val, tick ) );
Ok, the elements in the container are constant and may not be changed through iterators. For multiindex container the modify method must be used to change them. So I changed the last line to : boost::function<void(Statistics&)> fnAddStats = boost::bind( &Statistics::addStats, ::_1, val, tick ); for_each( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify, boost::ref(idxResponse), ::_1, fnAddStats ) ); but it still does not compile (problem with boost::bind "wrong number of arguments"). the call : idxResponse.modify( it, fnAddStats ); works, so the problem is not the first bind, but the one in for_each. -- Nebojsa Simic
Nebojsa Simic wrote:
Nebojsa Simic wrote:
Hello all,
First of all, thanks for a wonderful library, it is a pleasure to work with...
However I ran into some problems and I can not find the answers either on the Internet nor on this mailing list. The problem at hand concerns the multiindex container and bind.
I have a class with the following member:
class Statistics { public: void addStats ( double val, int tick ); }
and a container:
typedef multi_index_container< Statistics, indexed_by <ordered_unique<identity<Statistics> >, ordered_non_unique< member<Statistics,double,&Statistics::gamma> > >
StatisticsMap;
StatisticsMap m_statistic;
indexed by :
typedef StatisticsMap::nth_index<1>::type StatisticsByResponse;
somewhere in code i try to do this :
std::pair<StatisticsMap::iterator,bool> result = m_statistic.insert( Statistics( response, value, tick ) );
StatisticsByResponse& idxResponse = m_statistic.get<1>(); StatisticsByResponse::iterator it = m_statistic.project<1>(result.first );
the problem comes when I try to update the statistics by using :
for_each( it , idxResponse.end() , boost::bind( &Statistics::addStats, ::_1, val, tick ) );
Ok, the elements in the container are constant and may not be changed through iterators. For multiindex container the modify method must be used to change them.
So I changed the last line to :
boost::function<void(Statistics&)> fnAddStats = boost::bind( &Statistics::addStats, ::_1, val, tick );
for_each( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify, boost::ref(idxResponse), ::_1, fnAddStats ) );
but it still does not compile (problem with boost::bind "wrong number of arguments").
the call : idxResponse.modify( it, fnAddStats ); works, so the problem is not the first bind, but the one in for_each.
this compiles: boost::function<void(Statistics)> fnAddStats = boost::bind( &Statistics::addStats, ::_1, val, tick ); for_each( it , idxResponse.end() , fnAddStats ); but I do not think it works since the value is passed to the fnAddStats and not the reference. Any suggestions on how to update the members of the multiindex container between two iterators ? -- Nebojsa Simic
Hi Nebojsa, ----- Mensaje original ----- De: Nebojsa Simic <nelle@sbox.tugraz.at> Fecha: Sábado, Noviembre 17, 2007 0:05 am Asunto: Re: [Boost-users] [multiindex] [bind] Update members of the container between two iterators (was: Conversion loses qualifiers) Para: boost-users@lists.boost.org
Nebojsa Simic wrote: [...]
for_each( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify, boost::ref(idxResponse), ::_1, fnAddStats ) );
but it still does not compile (problem with boost::bind "wrong number of arguments").
the call : idxResponse.modify( it, fnAddStats ); works, so the problem is not the first bind, but the one in for_each.
[...]
You can't use for_each(it1,it2,someFunctor) to do what you want because modify() needs an iterator, and for_each passes a value reference to someFunctor rather than the iterator. So, you've got to resort to a handmade loop like: for(StatisticsByResponse::iterator it=m_statistic.project<1> (result.first), it_end=idxResponse.end(); it!=it_end;++it){ idxResponse.modify(it,boost::bind (&Statistics::addStats,::_1,val,tick)); } A warning about modifying elements of a multi_index_container in a loop: if your modification affects the key on which the index you're traversing depends upon, then the loop is broken, because when you call modify(...) the element will be rearranged in the index and along with it the iterator "it". If this is your case, please read the following post where mechanisms for range modifying are provided: http://lists.boost.org/boost-users/2006/03/18048.php (Note that post comes with some usable code attached). Hope this helps, thanks for using Boost.MultiIndex, if something's still not clear do not hesitate to come back. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
JOAQUIN LOPEZ MU?Z wrote:
Hi Nebojsa,
[...] Ola Joaquin, first of all thanks for the swift reply.
[...]
You can't use for_each(it1,it2,someFunctor) to do what you want because modify() needs an iterator, and for_each passes a value reference to someFunctor rather than the iterator.
Yes, I forgot that ...
So, you've got to resort to a handmade loop like:
for(StatisticsByResponse::iterator it=m_statistic.project<1> (result.first), it_end=idxResponse.end(); it!=it_end;++it){ idxResponse.modify(it,boost::bind (&Statistics::addStats,::_1,val,tick)); }
perfect.
A warning about modifying elements of a multi_index_container in a loop: if your modification affects the key on which the index you're traversing depends upon, then the loop is broken, because when you call modify(...) the element will be rearranged in the index and along with it the iterator "it". If this is your case, please read the following post where mechanisms for range modifying are provided:
http://lists.boost.org/boost-users/2006/03/18048.php
(Note that post comes with some usable code attached). Hope this helps, thanks for using Boost.MultiIndex, if something's still not clear do not hesitate to come back.
In this case it is not necessary, because the addStats modifies only the second index and not idxResponse. template<typename Index,typename Modifier> void modify_unstable_range( Index& i,typename Index::iterator first,typename Index::iterator last, Modifier mod) { typedef std::vector<typename Index::iterator> buffer_type; buffer_type v; v.reserve( last - first ); // would this help boost performance while(first!=last)v.push_back(first++); for(typename buffer_type::iterator it=v.begin(),it_end=v.end(); it!=it_end;i.modify(*it++,mod)); } -- Nebojsa Simic
JOAQUIN LOPEZ MU?Z wrote:
Hi Nebojsa,
----- Mensaje original ----- De: Nebojsa Simic <nelle@sbox.tugraz.at> Fecha: Sábado, Noviembre 17, 2007 0:05 am Asunto: Re: [Boost-users] [multiindex] [bind] Update members of the container between two iterators (was: Conversion loses qualifiers) Para: boost-users@lists.boost.org
Nebojsa Simic wrote: [...]
for_each( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify, boost::ref(idxResponse), ::_1, fnAddStats ) );
but it still does not compile (problem with boost::bind "wrong number of arguments").
the call : idxResponse.modify( it, fnAddStats ); works, so the problem is not the first bind, but the one in for_each. [...]
You can't use for_each(it1,it2,someFunctor) to do what you want because modify() needs an iterator, and for_each passes a value reference to someFunctor rather than the iterator. So, you've got to resort to a handmade loop like:
So, the current status is: // TEMPLATE FUNCTION for_each_it template<class _InIt, class _Fn1> inline _Fn1 for_each_it(_InIt _First, _InIt _Last, _Fn1 _Func) { // perform function for each element for (; _First != _Last; ++_First) _Func(_First); return (_Func); }; and when I try to do this : for_each_it( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify, idxResponse, ::_1, fnAddStats ) ); still get compilation errors. What am I missing here ? as a temporary solution I added : inline bool bloodyBindable( StatisticsByResponse& index, const StatisticsByResponse::iterator& it, boost::function<void(Statistics&)> fnc ) { return index.modify( it, fnc ); } for_each_it( it , idxResponse.end() , boost::bind( bloodyBindable, idxResponse, ::_1, fnAddW0 ) ); which compiles, but I just want to know what am I doing wrong. -- Nebojsa Simic
----- Mensaje original ----- De: Nebojsa Simic <nelle@sbox.tugraz.at> Fecha: Sábado, Noviembre 17, 2007 4:02 pm Asunto: Re: [Boost-users] [multiindex] [bind] Update members of the container between two iterators Para: boost-users@lists.boost.org
JOAQUIN LOPEZ MU?Z wrote: [...]
You can't use for_each(it1,it2,someFunctor) to do what you want because> modify() needs an iterator, and for_each passes a value reference> to someFunctor rather than the iterator. So, you've got to resort to a handmade loop like:
So, the current status is:
// TEMPLATE FUNCTION for_each_it template<class _InIt, class _Fn1> inline _Fn1 for_each_it(_InIt _First, _InIt _Last, _Fn1 _Func) { // perform function for each element for (; _First != _Last; ++_First) _Func(_First); return (_Func); };
and when I try to do this :
for_each_it( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify, idxResponse, ::_1, fnAddStats ) );
still get compilation errors. What am I missing here ?
as a temporary solution I added :
inline bool bloodyBindable( StatisticsByResponse& index, const StatisticsByResponse::iterator& it, boost::function<void(Statistics&)> fnc ) { return index.modify( it, fnc ); }
for_each_it( it , idxResponse.end() , boost::bind( bloodyBindable, idxResponse, ::_1, fnAddW0 ) );
which compiles, but I just want to know what am I doing wrong.
Two things: 1. The expression boost::bind(bloodyBindable,idxResponse,::_1,fnAddStats) does a copy of the idxResponse index, which is not what you want (indices are actually not copyable, more info on why you can still get spurious index copies in certain compilers at http://lists.boost.org/boost-users/2007/10/31777.php ). So, to prevent this copying use boost::ref: boost::bind(bloodyBindable,boost::ref(idxResponse),::_1,fnAddStats) More info on the usage of Boost.Ref with Boost.Bind at http://boost.org/libs/bind/bind.html . 2. The reason why you can't do the binding directly and have to resort to the bloodyBindable proxy is that modify is *not* a member function, but a member function *template*. To do the binding you have to provide an instantiation of modify, like this: for_each_it( it,idxResponse.end(), boost::bind( &StatisticsByResponse::modify<boost::function<void(Statistics)>
, boost::ref(idxResponse),::_1,fnAddStats));
Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
JOAQUIN LOPEZ MU?Z wrote:
----- Mensaje original -----
[...]
1. The expression
boost::bind(bloodyBindable,idxResponse,::_1,fnAddStats)
does a copy of the idxResponse index, which is not what you want (indices are actually not copyable, more info on why you can still get spurious index copies in certain compilers at http://lists.boost.org/boost-users/2007/10/31777.php ). So, to prevent this copying use boost::ref:
boost::bind(bloodyBindable,boost::ref(idxResponse),::_1,fnAddStats)
More info on the usage of Boost.Ref with Boost.Bind at http://boost.org/libs/bind/bind.html .
thanks for the tip, I already added the boost::ref ...
2. The reason why you can't do the binding directly and have to resort to the bloodyBindable proxy is that modify is *not* a member function, but a member function *template*. To do the binding you have to provide an instantiation of modify, like this:
for_each_it( it,idxResponse.end(), boost::bind( &StatisticsByResponse::modify<boost::function<void(Statistics)>
, boost::ref(idxResponse),::_1,fnAddStats));
I'm working with VS 2003 (Compiler Version 13.10.3077) and it does not like nested templates, so I tried doing the following : typedef boost::function<void(Statistics)> fnModifier; for_each_it( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify<fnModifier> , boost::ref(idxResponse) , ::_1 , fnAddW0 ) ); bind still cant find proper instantiation : "could not deduce template argument for 'overloaded function type' from 'overloaded function type'" Could this be a compiler issue ??? -- Nebojsa Simic
----- Mensaje original ----- De: Nebojsa Simic <nelle@sbox.tugraz.at> Fecha: Sábado, Noviembre 17, 2007 5:54 pm Asunto: Re: [Boost-users] [multiindex] [bind] Update members of the container between two iterators Para: boost-users@lists.boost.org [...]
I'm working with VS 2003 (Compiler Version 13.10.3077) and it does not like nested templates, so I tried doing the following :
typedef boost::function<void(Statistics)> fnModifier;
for_each_it( it , idxResponse.end() , boost::bind( &StatisticsByResponse::modify<fnModifier> , boost::ref(idxResponse) , ::_1 , fnAddW0 ) );
bind still cant find proper instantiation : "could not deduce template argument for 'overloaded function type' from'overloaded function type'"
Could this be a compiler issue ???
I'd say so: the code compiles fine here with VS 2005. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
participants (2)
-
"JOAQUIN LOPEZ MU?Z"
-
Nebojsa Simic