Problem with sub_range

Hi, I am not sure if it is the proper newsgroup to get answers related to boost usage. I am facing a problem with boost::sub_range for a const container which is not allowing me to access the indexed operator. Below a short program to demonstrate the problem. Necessary headers are included. Boost version 1.33.1 typedef vector<int> VI; VI v(10); int data[] = {0,1,2,3,4,5,6,7,8,9}; copy(data,data+10,v.begin());///inserted a few int to std::vector<int> ///prints 0 1 2 3 4 5 6 7 8 9 copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<endl; const VI& cv = v; /// a const reference to the container. VI::iterator it = v.begin(); ///got an random access iterator it[1] = 100; /// index operator allows to change it copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<endl; ///prints 0 100 2 3 4 ... VI::const_iterator it1 = v.begin(); ///got a const_iterator cout<<it1[1]<<endl; /// returns const_reference, assignment is not allowed, access is allowed. prints 100 boost::sub_range<VI> r(v.begin()+2,v.begin()+8); ///got a sub_range ///prints 2 3 4 5 6 7 copy(r.begin(),r.end(),ostream_iterator<int>(cout," ")); cout<<endl; r[2] = 400; cout<<r[2]<<endl;/// prints 400 ///prints 2 3 400 5 6 7 copy(r.begin(),r.end(),ostream_iterator<int>(cout," ")); ///so far everything is fine. Here problem starts /// a const sub_range ? boost::sub_range<const VI> r1(cv.begin()+2,cv.begin()+8); ///prints 2 3 400 5 6 7 copy(r1.begin(),r1.end(),ostream_iterator<int>(cout," "));cout<<endl; ///next statement is don't compile cout<<r1[2]<<endl; ///=> not allowed gives error under Visual Studio 7.1 cannot convert from 'const std::allocator<_Ty>::value_type' to 'boost::iterator_range<IteratorT>::value_type &' Why it tried to convert it to value_type& instead of const value_type& ? cout<<typeid(r1.begin()).name()<<endl; says r1.begin() is a const_iteartor. So the statement cout<<r1[2]<<endl; should return a const_reference. Am I mis interpreting the const version of sub_range ? If so, what is a const counterpart of sub_range, which behaves just like a pair of const_iterator ? Any help is appreciated. Thanks abir

abir basak wrote:
Hi, I am not sure if it is the proper newsgroup to get answers related to boost usage. I am facing a problem with boost::sub_range for a const container which is not allowing me to access the indexed operator. Below a short program to demonstrate the problem. Necessary headers are included. Boost version 1.33.1 typedef vector<int> VI; VI v(10); int data[] = {0,1,2,3,4,5,6,7,8,9}; copy(data,data+10,v.begin());///inserted a few int to std::vector<int>
Hm... this is not legal. May I suggest v = boost::assign::list_of(0)(1)(2)(3)(4)(5)(6) ... ; ?
///prints 0 1 2 3 4 5 6 7 8 9 copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<endl; const VI& cv = v; /// a const reference to the container. VI::iterator it = v.begin(); ///got an random access iterator it[1] = 100; /// index operator allows to change it copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<endl; ///prints 0 100 2 3 4 ... VI::const_iterator it1 = v.begin(); ///got a const_iterator cout<<it1[1]<<endl; /// returns const_reference, assignment is not allowed, access is allowed. prints 100 boost::sub_range<VI> r(v.begin()+2,v.begin()+8); ///got a sub_range ///prints 2 3 4 5 6 7 copy(r.begin(),r.end(),ostream_iterator<int>(cout," ")); cout<<endl; r[2] = 400; cout<<r[2]<<endl;/// prints 400 ///prints 2 3 400 5 6 7 copy(r.begin(),r.end(),ostream_iterator<int>(cout," ")); ///so far everything is fine. Here problem starts /// a const sub_range ? boost::sub_range<const VI> r1(cv.begin()+2,cv.begin()+8); ///prints 2 3 400 5 6 7 copy(r1.begin(),r1.end(),ostream_iterator<int>(cout," "));cout<<endl; ///next statement is don't compile cout<<r1[2]<<endl; ///=> not allowed gives error under Visual Studio 7.1 cannot convert from 'const std::allocator<_Ty>::value_type' to 'boost::iterator_range<IteratorT>::value_type &' Why it tried to convert it to value_type& instead of const value_type& ? cout<<typeid(r1.begin()).name()<<endl; says r1.begin() is a const_iteartor. So the statement cout<<r1[2]<<endl; should return a const_reference. Am I mis interpreting the const version of sub_range ? If so, what is a const counterpart of sub_range, which behaves just like a pair of const_iterator ?
This is an error in the range lib that should be fixed in the upcoming version of boost. -Thorsten

On 11/17/06, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
typedef vector<int> VI; VI v(10); int data[] = {0,1,2,3,4,5,6,7,8,9}; copy(data,data+10,v.begin());///inserted a few int to std::vector<int>
Hm... this is not legal.
Sorry, why? The constructor makes the size 10, so isn't there space to copy in the 10 elements? ~ SWMc

me22 wrote:
On 11/17/06, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
typedef vector<int> VI; VI v(10); int data[] = {0,1,2,3,4,5,6,7,8,9}; copy(data,data+10,v.begin());///inserted a few int to std::vector<int>
Hm... this is not legal.
Sorry, why?
The constructor makes the size 10, so isn't there space to copy in the 10 elements?
Right. My bad. -Thorsten

Thorsten Ottosen wrote:
abir basak wrote:
Hi, I am not sure if it is the proper newsgroup to get answers related to boost usage. I am facing a problem with boost::sub_range for a const container which is not allowing me to access the indexed operator. Below a short program to demonstrate the problem. Necessary headers are included. Boost version 1.33.1 typedef vector<int> VI; VI v(10); int data[] = {0,1,2,3,4,5,6,7,8,9}; copy(data,data+10,v.begin());///inserted a few int to std::vector<int>
Hm... this is not legal. It is "not legal" or "not preferred" ? I think it is legal, as I have a statement like VI v(10); rather than VI v; copy doesn't grow memory, or change size. But here I am just copying! Of course the other (and better ) way is, VI v; int data[] = {0,1,2,3,4,5,6,7,8,9}; v.assign(data,data+10);
May I suggest
v = boost::assign::list_of(0)(1)(2)(3)(4)(5)(6) ... ;
?
///prints 0 1 2 3 4 5 6 7 8 9 copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<endl; const VI& cv = v; /// a const reference to the container. VI::iterator it = v.begin(); ///got an random access iterator it[1] = 100; /// index operator allows to change it copy(v.begin(),v.end(),ostream_iterator<int>(cout," ")); cout<<endl; ///prints 0 100 2 3 4 ... VI::const_iterator it1 = v.begin(); ///got a const_iterator cout<<it1[1]<<endl; /// returns const_reference, assignment is not allowed, access is allowed. prints 100 boost::sub_range<VI> r(v.begin()+2,v.begin()+8); ///got a sub_range ///prints 2 3 4 5 6 7 copy(r.begin(),r.end(),ostream_iterator<int>(cout," ")); cout<<endl; r[2] = 400; cout<<r[2]<<endl;/// prints 400 ///prints 2 3 400 5 6 7 copy(r.begin(),r.end(),ostream_iterator<int>(cout," ")); ///so far everything is fine. Here problem starts /// a const sub_range ? boost::sub_range<const VI> r1(cv.begin()+2,cv.begin()+8); ///prints 2 3 400 5 6 7 copy(r1.begin(),r1.end(),ostream_iterator<int>(cout," "));cout<<endl; ///next statement is don't compile cout<<r1[2]<<endl; ///=> not allowed gives error under Visual Studio 7.1 cannot convert from 'const std::allocator<_Ty>::value_type' to 'boost::iterator_range<IteratorT>::value_type &' Why it tried to convert it to value_type& instead of const value_type& ? cout<<typeid(r1.begin()).name()<<endl; says r1.begin() is a const_iteartor. So the statement cout<<r1[2]<<endl; should return a const_reference. Am I mis interpreting the const version of sub_range ? If so, what is a const counterpart of sub_range, which behaves just like a pair of const_iterator ?
This is an error in the range lib that should be fixed in the upcoming version of boost. Is the correction is in the CVS head ? Or can you suggest what should be the correction, if it is a small correction? Thanks for answering. abir -Thorsten

Thorsten Ottosen wrote:
abir basak wrote:
Thorsten Ottosen wrote:
This is an error in the range lib that should be fixed in the upcoming version of boost. Is the correction is in the CVS head ?
Should be. Try it out and let me know the result. Checked with the boost cvs version (downloaded only range library, i.e. only the files inside the range folder , and the range.hpp file ). It gives the same kind of error in little different manner. For the line like, boost::sub_range<const VI> r1(v.begin()+2,v.begin()+8); or boost::sub_range<const VI> r1(cv.begin()+2,cv.begin()+8); (The code is with reference to last post ) Gives error for the statement cout<<r1[1]<<endl; (i.e access by index) as (in my VC 2003 compiler , version 7.1) e:\boost_1_33_1\boost\range\sub_range.hpp(133): error C2440: 'return' : cannot convert from 'const std::allocator<_Ty>::value_type' to 'boost::sub_range<ForwardRange>::value_type &' with [ _Ty=int ] and [ ForwardRange=const VI ] Conversion loses qualifiers e:\boost_1_33_1\boost\range\sub_range.hpp(132) : while compiling class-template member function 'boost::sub_range<ForwardRange>::value_type &boost::sub_range<ForwardRange>::operator [](boost::sub_range<ForwardRange>::size_type)' with [ ForwardRange=const VI ] f:\abir\programs\Test\main.cpp(253) : see reference to class template instantiation 'boost::sub_range<ForwardRange>' being compiled with [ ForwardRange=const VI ] Quickly going through the code, I see it calls value_type& operator[]( size_type sz ) { return base::operator[](sz); } for a sub_range with const container, which returns value_type& rather than const value_type& . It fails in a way, that it don't know whether container is const or not (though it knows iterators are const or not).
And, it perfectly works, as expected if the code is modified like, const boost::sub_range<const VI> r1(v.begin()+2,v.begin()+8); ///note the range is also made const along with the container. as it now calls, const value_type& operator[]( size_type sz ) const { return base::operator[](sz); } Thus const_sub_range is not like "sub_range<const container_type>", rather strangely it is "const sub_range<const container_type>" which is little different that the iterator concept. The problem lies is that a const_sub_range is not same as const sub_range, just like const_iterator is not same as const iterator. For const_iterator, even non const member function need to return a const_reference, and should be same for sub_range. I am not sure, how a single class can know the const-ness of the container, and hence invoke additional method, without passing an additional argument or having two different class. For second type, it may be the same as the way SGI iterator and const_iterator are implemented. The first way is to have a sub_range template definition as, template<typename container_type, typename elem_type = container::value_type> and then return elem_type for the operators, irrespective of const-ness of the member function. The user has the responsibility to say it explicitly like boost::sub_range<VI> r(...); ///for non const version. boost::sub_range<const VI,VI::const_reference> r(...); ///for const version. I think, as most of the STL containers internally do this as typedef, and return iterator by themselves, it is not a problem. However when the sub_range is returned "externally using the container", I am not sure any other method works for const version. I will be glad if someone can show a way to know where a template parameter is const, as that will help me in many other part of the codes also (I am little fond of const-ness and use it as much as possible). Thanks to the Boost community. abir basak
-Thorsten

abir basak wrote:
Thorsten Ottosen wrote:
I will be glad if someone can show a way to know where a template parameter is const, as that will help me in many other part of the codes also (I am little fond of const-ness and use it as much as possible).
I checked with the release candidate, and it differs from the cvs head for sub_range.hpp. If you try the release candidate it should work. The difference is that the release candidate uses iterator_reference instead of value_type&. cheers -Thorsten

Thorsten Ottosen wrote:
abir basak wrote:
Thorsten Ottosen wrote:
I will be glad if someone can show a way to know where a template parameter is const, as that will help me in many other part of the codes also (I am little fond of const-ness and use it as much as possible).
I checked with the release candidate, and it differs from the cvs head for sub_range.hpp. If you try the release candidate it should work.
The difference is that the release candidate uses iterator_reference instead of value_type&.
cheers
-Thorsten RC_1_34 works. Revision 1.21. To my surprise, Revision 1.23 (HEAD) changed it to value_type& and const value_type& ! Many many thanks . abir basak
-- Abir Basak, Member IEEE Software Engineer, Read Ink Technologies B. Tech, IIT Kharagpur email: abir@abirbasak.com homepage: www.abirbasak.com
participants (3)
-
abir basak
-
me22
-
Thorsten Ottosen