[multi-index][foreach] Iterating over a sequence index (worked in 1.46, broke in 1.47)
Hi, I use BOOST_FOREACH to iterate of a BMI with a sequence index. The code used to work with Boost 1.46 and before, but broke with Boost 1.47. Am I doing something wrong ? ------------------------ #include <iostream> # include <boost/multi_index/hashed_index.hpp> # include <boost/multi_index/member.hpp> # include <boost/multi_index/sequenced_index.hpp> # include <boost/multi_index_container.hpp> # include <boost/foreach.hpp> using namespace ::boost::multi_index; typedef multi_index_container< int, indexed_by< sequenced<> > > bmi_t; typedef bmi_t::nth_index<0>::type seq_idx; const seq_idx& ret(const seq_idx& idx) { return idx; } int main() { bmi_t b; seq_idx& seq = b.get<0>(); // Works BOOST_FOREACH (int i, seq) std::cout << i << std::endl; // Doesn't compile BOOST_FOREACH (int i, ret(seq)) std::cout << i << std::endl; } ------------------------ Note that the offending part is the 'ret(seq)', without it, the code compiles. The error with g++ 4.6.1 is:
In file included from bmi.cc:9:0: /home/yabo/dev/boost/usr/include/boost/multi_index/sequenced_index.hpp: In destructor ‘boost::foreach_detail_::simple_variant<T>::~simple_variant() [with T = boost::multi_index::detail::sequenced_index<boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, boost::mpl::vector0<mpl_::na> >]’: /home/yabo/dev/boost/usr/include/boost/foreach.hpp:256:8: instantiated from here /home/yabo/dev/boost/usr/include/boost/multi_index/sequenced_index.hpp:561:3: error: ‘boost::multi_index::detail::sequenced_index<SuperMeta, TagList>::~sequenced_index() [with SuperMeta = boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, TagList = boost::mpl::vector0<mpl_::na>]’ is protected /home/yabo/dev/boost/usr/include/boost/foreach.hpp:586:13: error: within this context /home/yabo/dev/boost/usr/include/boost/multi_index/sequenced_index.hpp: In constructor ‘boost::foreach_detail_::simple_variant<T>::simple_variant(const T&) [with T = boost::multi_index::detail::sequenced_index<boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, boost::mpl::vector0<mpl_::na> >]’: /home/yabo/dev/boost/usr/include/boost/foreach.hpp:648:95: instantiated from ‘boost::foreach_detail_::auto_any<boost::foreach_detail_::simple_variant<T> > boost::foreach_detail_::contain(const T&, bool*) [with T = boost::multi_index::detail::sequenced_index<boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, boost::mpl::vector0<mpl_::na> >]’ bmi.cc:28:3: instantiated from here /home/yabo/dev/boost/usr/include/boost/multi_index/sequenced_index.hpp:549:3: error: ‘boost::multi_index::detail::sequenced_index<SuperMeta, TagList>::sequenced_index(const boost::multi_index::detail::sequenced_index<SuperMeta, TagList>&) [with SuperMeta = boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, TagList = boost::mpl::vector0<mpl_::na>]’ is protected /home/yabo/dev/boost/usr/include/boost/foreach.hpp:571:9: error: within this context /home/yabo/dev/boost/usr/include/boost/multi_index/sequenced_index.hpp: In copy constructor ‘boost::foreach_detail_::simple_variant<T>::simple_variant(const boost::foreach_detail_::simple_variant<T>&) [with T = boost::multi_index::detail::sequenced_index<boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, boost::mpl::vector0<mpl_::na> >, boost::foreach_detail_::simple_variant<T> = boost::foreach_detail_::simple_variant<boost::multi_index::detail::sequenced_index<boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, boost::mpl::vector0<mpl_::na> > >]’: /home/yabo/dev/boost/usr/include/boost/foreach.hpp:256:8: instantiated from ‘boost::foreach_detail_::auto_any<boost::foreach_detail_::simple_variant<T> > boost::foreach_detail_::contain(const T&, bool*) [with T = boost::multi_index::detail::sequenced_index<boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, boost::mpl::vector0<mpl_::na> >]’ bmi.cc:28:3: instantiated from here /home/yabo/dev/boost/usr/include/boost/multi_index/sequenced_index.hpp:549:3: error: ‘boost::multi_index::detail::sequenced_index<SuperMeta, TagList>::sequenced_index(const boost::multi_index::detail::sequenced_index<SuperMeta, TagList>&) [with SuperMeta = boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::sequenced<> >, std::allocator<int> >, TagList = boost::mpl::vector0<mpl_::na>]’ is protected /home/yabo/dev/boost/usr/include/boost/foreach.hpp:578:13: error: within this context
Note that with clang++ 2.9 the code doesn't compile at all either with Boost 1.46 or Boost 1.47. Thanks! -- Maxime
typedef multi_index_container< int, indexed_by< sequenced<> > > bmi_t; typedef bmi_t::nth_index<0>::type seq_idx;
const seq_idx& ret(const seq_idx& idx) { return idx; }
int main() {
bmi_t b;
seq_idx& seq = b.get<0>();
// Works BOOST_FOREACH (int i, seq) std::cout << i << std::endl;
// Doesn't compile BOOST_FOREACH (int i, ret(seq)) std::cout << i << std::endl; }
It seems that gcc attempts to copy the index, for some reason. BTW, your code compiles well with VC10.
Maxime van Noppen wrote:
On 07/29/2011 09:36 AM, Igor R wrote:
It seems that gcc attempts to copy the index, for some reason.
BTW, your code compiles well with VC10.
So it looks like it's a g++ and clang++ bug ?
It's not a bug. GCC 4.6 (in C++03 mode) changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach; then compilation error occurs. To detect detecting lvalue/rvalue, Boost.Foreach tries to copy `sequenced_index` (though the copy is never executed…). However, the copy ctor of `sequenced_index` is protected, and so the compile error emitted. To compile the code please add the following code: namespace boost { namespace foreach { template<typename SuperMeta,typename TagList> struct is_noncopyable< boost::multi_index::detail::sequenced_index<SuperMeta, TagList> > : mpl::true_ {}; }} Regards, Michel
Michel MORIN wrote:
GCC 4.6 (in C++03 mode) changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach; then compilation error occurs.
Minor correction: GCC 4.6 changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach; then compilation error occurs in C++03 mode of GCC 4.6. Regards, Michel
On 07/29/2011 10:03 AM, Michel MORIN wrote:
To compile the code please add the following code: namespace boost { namespace foreach { template<typename SuperMeta,typename TagList> struct is_noncopyable< boost::multi_index::detail::sequenced_index<SuperMeta, TagList> > : mpl::true_ {}; }}
Works! Great! Thank you very much. Should I create a ticket with this for Foreach or Multi-Index? Or is it already fixed in trunk? -- Maxime
Maxime van Noppen wrote:
On 07/29/2011 10:03 AM, Michel MORIN wrote:
To compile the code please add the following code: namespace boost { namespace foreach { template<typename SuperMeta,typename TagList> struct is_noncopyable< boost::multi_index::detail::sequenced_index<SuperMeta, TagList> > : mpl::true_ {}; }}
Works! Great! Thank you very much. Should I create a ticket with this for Foreach or Multi-Index? Or is it already fixed in trunk?
I think it's a feature request for Multi-Index. Please create a ticket! Regards, Michel
El 29/07/2011 10:52, Michel MORIN escribió:
Maxime van Noppen wrote:
On 07/29/2011 10:03 AM, Michel MORIN wrote:
To compile the code please add the following code: namespace boost { namespace foreach { template<typename SuperMeta,typename TagList> struct is_noncopyable< boost::multi_index::detail::sequenced_index<SuperMeta, TagList> > : mpl::true_ {}; }}
Works! Great! Thank you very much. Should I create a ticket with this for Foreach or Multi-Index? Or is it already fixed in trunk? I think it's a feature request for Multi-Index. Please create a ticket!
Ticket closed by https://svn.boost.org/trac/boost/changeset/73498 Would you care to test it locally to confirm everything works? Thank you! Joaquín M López Muñoz Telefónica, Investigación y Desarrollo Este mensaje se dirige exclusivamente a su destinatario. Puede consultar nuestra política de envío y recepción de correo electrónico en el enlace situado más abajo. This message is intended exclusively for its addressee. We only send and receive email on the basis of the terms set out at. http://www.tid.es/ES/PAGINAS/disclaimer.aspx
joaquin@tid.es wrote:
Ticket closed by
https://svn.boost.org/trac/boost/changeset/73498
Would you care to test it locally to confirm everything works? Thank you!
Works flawlessly! (I tested the OP's code and the test case in #5741 with gcc-4.6 and clang.) `libs/multi_index/test` runs successfully, too. Thanks for fixing this. Regards, Michel
Michel MORIN <mimomorin <at> gmail.com> writes:
Maxime van Noppen wrote:
On 07/29/2011 09:36 AM, Igor R wrote:
It seems that gcc attempts to copy the index, for some reason.
BTW, your code compiles well with VC10.
So it looks like it's a g++ and clang++ bug ?
It's not a bug.
GCC 4.6 (in C++03 mode) changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach; then compilation error occurs.
To detect detecting lvalue/rvalue, Boost.Foreach tries to copy `sequenced_index` (though the copy is never executed…). However, the copy ctor of `sequenced_index` is protected, and so the compile error emitted.
I understand the problem and will have no problem in fixing it from Boost.MultiIndex side since there is a documented way to do that in Boost.Foreach, but before doing that I'd like to know what's the opinion of Eric on this, since no such workaround was needed for prior versions of Boost.Foreach. I'll post a separate queswtion and act accordingly to the results. Best, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Michel MORIN <mimomorin <at> gmail.com> writes:
GCC 4.6 (in C++03 mode) changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach; then compilation error occurs.
To detect detecting lvalue/rvalue, Boost.Foreach tries to copy `sequenced_index` (though the copy is never executed…). However, the copy ctor of `sequenced_index` is protected, and so the compile error emitted.
This description might be insufficient. So let me explain it again. GCC 4.6 changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach: * On GCC 4.6, Boost.Foreach detects it at run time. * On GCC 4.5 and prior versions, Boost.Foreach detects it at compile time. (Note that, in Boost 1.46 and prior versions, Boost.Foreach incorrectly uses compile-time detection on GCC 4.6.) When detecting lvalue/rvalue at run time, Boost.Foreach tries to copy `sequenced_index`. However, its copy ctor is protected, and so the compile error emitted. To avoid this, we need to tell Boost.Foreach not to copy `sequenced_index` by specializing `is_noncopyable` or overloading `boost_foreach_is_noncopyable`. Compile-time lvalue/rvalue detection does not cause any problem with `sequenced_index`. Considering the fact that many compilers (VC++ 7.1 and newer versions, GCC 3.4-4.5) support compile-time detection, it is not surprising that the compatibility issue between Boost.MultiIndex and Boost.Foreach did not occur in the past. But it's just that the problem did not surface in the past; on compilers that use run-time detection, the problem has existed from the beginning. Regards, Michel
On 7/31/2011 1:34 PM, Michel MORIN wrote:
Michel MORIN <mimomorin <at> gmail.com> writes:
GCC 4.6 (in C++03 mode) changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach; then compilation error occurs.
To detect detecting lvalue/rvalue, Boost.Foreach tries to copy `sequenced_index` (though the copy is never executed…). However, the copy ctor of `sequenced_index` is protected, and so the compile error emitted.
This description might be insufficient. So let me explain it again.
GCC 4.6 changes the behavior of rvalue conversion. This affects the way of lvalue/rvalue detection in Boost.Foreach: * On GCC 4.6, Boost.Foreach detects it at run time. * On GCC 4.5 and prior versions, Boost.Foreach detects it at compile time. (Note that, in Boost 1.46 and prior versions, Boost.Foreach incorrectly uses compile-time detection on GCC 4.6.)
When detecting lvalue/rvalue at run time, Boost.Foreach tries to copy `sequenced_index`. However, its copy ctor is protected, and so the compile error emitted. To avoid this, we need to tell Boost.Foreach not to copy `sequenced_index` by specializing `is_noncopyable` or overloading `boost_foreach_is_noncopyable`.
Compile-time lvalue/rvalue detection does not cause any problem with `sequenced_index`. Considering the fact that many compilers (VC++ 7.1 and newer versions, GCC 3.4-4.5) support compile-time detection,
"Support" isn't the right word. They have compiler bugs that Foreach can exploit to get the information it needs. Gcc had such bugs until v4.6, but now it doesn't, hence the trouble.
it is not surprising that the compatibility issue between Boost.MultiIndex and Boost.Foreach did not occur in the past. But it's just that the problem did not surface in the past; on compilers that use run-time detection, the problem has existed from the beginning.
Exactly right. Thank you Michel. -- Eric Niebler BoostPro Computing http://www.boostpro.com
Eric Niebler wrote:
Compile-time lvalue/rvalue detection does not cause any problem with `sequenced_index`. Considering the fact that many compilers (VC++ 7.1 and newer versions, GCC 3.4-4.5) support compile-time detection,
"Support" isn't the right word. They have compiler bugs that Foreach can exploit to get the information it needs. Gcc had such bugs until v4.6, but now it doesn't, hence the trouble.
it is not surprising that the compatibility issue between Boost.MultiIndex and Boost.Foreach did not occur in the past. But it's just that the problem did not surface in the past; on compilers that use run-time detection, the problem has existed from the beginning.
Exactly right. Thank you Michel.
Eric, your descriptions are always clear, concise and getting the point. Admirable skill that I have to develop! Regards, Michel
participants (6)
-
Eric Niebler
-
Igor R
-
Joaquin M Lopez Munoz
-
joaquin@tid.es
-
Maxime van Noppen
-
Michel MORIN