[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
StatisticsMap;
StatisticsMap m_statistic;
indexed by :
typedef StatisticsMap::nth_index<1>::type StatisticsByResponse;
somewhere in code i try to do this :
std::pairStatisticsMap::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
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_non_unique< member > > StatisticsMap;
StatisticsMap m_statistic;
indexed by :
typedef StatisticsMap::nth_index<1>::type StatisticsByResponse;
somewhere in code i try to do this :
std::pairStatisticsMap::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
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_non_unique< member > > StatisticsMap;
StatisticsMap m_statistic;
indexed by :
typedef StatisticsMap::nth_index<1>::type StatisticsByResponse;
somewhere in code i try to do this :
std::pairStatisticsMap::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
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
Hi Nebojsa,
----- Mensaje original -----
De: Nebojsa Simic
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
JOAQUIN LOPEZ MU?Z wrote:
Hi Nebojsa,
----- Mensaje original ----- De: Nebojsa Simic
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
----- Mensaje original -----
De: Nebojsa Simic
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
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
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::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::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
----- Mensaje original -----
De: Nebojsa Simic
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
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