Opened 8 years ago

Last modified 8 years ago

#10514 new Bugs

Cannot copy const sub_range to non-const

Reported by: Braden McDaniel <braden@…> Owned by: Neil Groves
Milestone: To Be Determined Component: range
Version: Boost 1.56.0 Severity: Regression
Keywords: Cc:

Description

The following code does not compile with Visual Studio 2013 using Boost 1.56.0:

typedef std::vector<int> vec_t;
typedef boost::sub_range<vec_t> range_t;
vec_t vec(10);
range_t r(vec.begin(), vec.end());
const range_t & r_ref = r;
range_t v = r_ref;

The following error results:

boost/range/iterator_range_core.hpp(69) : error C2440: 'static_cast' : cannot convert from 'std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<int>>>' to 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>'
        No constructor could take the source type, or constructor overload resolution was ambiguous
        c:\build\ng-10.5-x64\API\inc\boost/range/sub_range.hpp(184) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_begin<const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag>>(const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag> &)' being compiled
        with
        [
            IteratorT=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
,            ForwardRange=vec_t
        ]
        c:\build\ng-10.5-x64\API\inc\boost/range/sub_range.hpp(187) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_begin<const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag>>(const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag> &)' being compiled
        with
        [
            IteratorT=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
,            ForwardRange=vec_t
        ]
        c:\build\ng-10.5-x64\API\inc\boost/range/sub_range.hpp(184) : while compiling class template member function 'boost::sub_range<vec_t>::sub_range(const boost::sub_range<vec_t> &)'
        sub_range_test.cpp(11) : see reference to function template instantiation 'boost::sub_range<vec_t>::sub_range(const boost::sub_range<vec_t> &)' being compiled
        sub_range_test.cpp(9) : see reference to class template instantiation 'boost::sub_range<vec_t>' being compiled
boost/range/iterator_range_core.hpp(75) : error C2440: 'static_cast' : cannot convert from 'std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<int>>>' to 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>'
        No constructor could take the source type, or constructor overload resolution was ambiguous
        c:\build\ng-10.5-x64\API\inc\boost/range/sub_range.hpp(186) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_end<const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag>>(const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag> &)' being compiled
        with
        [
            IteratorT=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
,            ForwardRange=vec_t
        ]
        c:\build\ng-10.5-x64\API\inc\boost/range/sub_range.hpp(187) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_end<const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag>>(const boost::range_detail::sub_range_base<ForwardRange,boost::random_access_traversal_tag> &)' being compiled
        with
        [
            IteratorT=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
,            ForwardRange=vec_t
        ]

So it looks as though having a const sub_range implies that it uses const_iterators, which doesn't seem appropriate.

Code of this nature compiled using Boost 1.55.0.

Attachments (1)

sub_range_test.cpp (254 bytes ) - added by Braden McDaniel <braden@…> 8 years ago.
Test case

Download all attachments as: .zip

Change History (5)

by Braden McDaniel <braden@…>, 8 years ago

Attachment: sub_range_test.cpp added

Test case

comment:1 by Neil Groves, 8 years ago

Resolution: invalid
Status: newclosed

The propagation of const-ness is the rationale for having sub_range in addition to iterator_range. Please see: http://www.boost.org/doc/libs/1_57_0/libs/range/doc/html/range/reference/utilities/sub_range.html

If you do not wish to propagate const-ness please use iterator_range instead.

in reply to:  1 comment:2 by Braden McDaniel <braden@…>, 8 years ago

Resolution: invalid
Status: closedreopened

Replying to neilgroves:

The propagation of const-ness is the rationale for having sub_range in addition to iterator_range. Please see: http://www.boost.org/doc/libs/1_57_0/libs/range/doc/html/range/reference/utilities/sub_range.html

If you do not wish to propagate const-ness please use iterator_range instead.

It appears to me that const is being propagating incorrectly in this case. At the very least, const is being propagated in a way that is inconsistent with how it is normally propagated with the standard containers. Consider the analogous example using just std::vector:

std::vector<int> v(10);
const std::vector<int> & v_ref = v;
std::vector<int> u = v_ref;

This compiles just fine because there is no problem copying a const int to an int. To the point: it doesn't matter that v_ref uses const_iterators.

(So, I may have framed the problem incorrectly in my initial description. The problem isn't that const_iterators are being used at all; the problem is that sub_range seems to insist that the lhs use const_iterators just because the rhs does.)

comment:3 by Neil Groves, 8 years ago

Status: reopenednew

I didn't comprehend initially that the snippet of code posted compiled with 1.55. I apologise for not understanding this despite you correctly putting the severity as regression.

Upon closer inspection this does appear like it ought to compile but not for the reasons you described. It is indeed intended for a const sub_range to return const_iterator. The strange issue is that const_iterator is not converting to iterator. This might be related to a problem in Boost 1.57 where Boost.Range had some specialisations of Boost.Iterator and Boost.Iterator had the namespace changed for the class specialised within Boost.Range. If it is related to this, then the "develop" and "master" branch of Boost.Range already contain a fix.

I have to do my day job for a bit, but I'll get back to looking at this as soon as I can. I don't have any Microsoft C++ compilers other than the free ones anymore. Hopefully this will show up on Clang or GCC when I try them.

Depending on the urgency of this defect, you may wish to pull the branches to see if they solve the problem. I'm aiming to look at this again later tonight.

comment:4 by Neil Groves, 8 years ago

Okay, I added a unit test for the scenario provided to the develop branch and it compiles cleanly. I believe that the problem has already been fixed. I think it is related to the missed template specialisation due to a mismatch between my specialisation and the changed namespace in Boost.Iterator.

I will not close the defect just yet. I'll watch this test cycle, and look closely at the MSVC regression tests. Hopefully these will pass, and I can just do a simple merge for release 1.58 to add this test case to ensure this doesn't happen again.

Sorry for the hassle.

Note: See TracTickets for help on using tickets.