
#include <boost/range.hpp> #include <vector> template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {} int main() { std::vector<int> out (2); copy (boost::make_iterator_range (out.begin(), out.begin()+2), boost::make_iterator_range (out.begin(), out.begin()+2)); } wrap/test.cc:12: error: invalid initialization of non-const reference of type 'boost::iterator_range<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >&' from a temporary of type 'boost::iterator_range<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >' wrap/test.cc:6: error: in passing argument 2 of 'void copy(const in_t&, out_t&) [with in_t = boost::iterator_range<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >, out_t = boost::iterator_range<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >]'

Thorsten Ottosen wrote:
Neal Becker wrote:
#include <boost/range.hpp> #include <vector>
template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {}
What makes you think you can bind a temporary to an non-const reference (out)?
Yeah, same old problem. I think the c+ standard should be changed. It's quite clear (to me) that this is an important use of the range concept. In the meantime, here's a workaround: template<class T> inline T& lvalue_cast (const T& rvalue) { return const_cast<T&> (rvalue); } template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {} int main() { std::vector<int> out (2); copy (boost::sub_range<std::vector<int> > (out.begin(), out.begin()+2), lvalue_cast (boost::sub_range<std::vector<int> > (out.begin(), out.begin()+2))); }

Neal Becker wrote:
Thorsten Ottosen wrote:
Neal Becker wrote:
#include <boost/range.hpp> #include <vector>
template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {}
What makes you think you can bind a temporary to an non-const reference (out)?
Yeah, same old problem. I think the c+ standard should be changed.
Well, && will help some.
It's quite clear (to me) that this is an important use of the range concept.
I think the algorothm is wrong in this case. I would go for template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, WriteForwardRange& ); template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, const WriteForwardRange& ); (which in C++0x can become one function using &&). -Thorsten

Thorsten Ottosen wrote:
Neal Becker wrote:
Thorsten Ottosen wrote:
Neal Becker wrote:
#include <boost/range.hpp> #include <vector>
template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {}
What makes you think you can bind a temporary to an non-const reference (out)?
Yeah, same old problem. I think the c+ standard should be changed.
Well, && will help some.
It's quite clear (to me) that this is an important use of the range concept.
I think the algorothm is wrong in this case. I would go for
template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, WriteForwardRange& );
template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, const WriteForwardRange& );
Did you mean something like this? --------------------------- #include <boost/range.hpp> #include <algorithm> #include <vector> template<typename in_t, typename out_t> void copy (in_t const& in, out_t const& out) { std::copy (boost::begin (in), boost::end (in), boost::begin (out)); } int main() { std::vector<int> out (2); copy (boost::sub_range<std::vector<int> > (out.begin(), out.begin()+2), boost::sub_range<std::vector<int> > (out.begin(), out.begin()+2)); } ----------------------------- Doesn't work, of course. The call to '::copy' now matches but this doesn't solve the basic problem: g++ -o wrap.x86_64/test.os -c -g -DNDEBUG -DBOOST_DISABLE_THREADS -O3 -ftree-vectorize -ffast-math -fstrict-aliasing -Wall -fPIC -Isrc -I/usr/local/src/boost.cvs -I/usr/include/python2.4 -Isrc-fixed -Isrc wrap/test.cc /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algobase.h: In function '_OI std::__copy_aux(_II, _II, _OI) [with _II = const int*, _OI = const int*]': /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algobase.h:354: instantiated from 'static _OI std::__copy_normal<true, true>::copy_n(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >, _OI = __gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >]' /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algobase.h:387: instantiated from '_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >, _OutputIterator = __gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >]' wrap/test.cc:12: instantiated from 'void copy(const in_t&, const out_t&) [with in_t = boost::sub_range<std::vector<int, std::allocator<int> > >, out_t = boost::sub_range<std::vector<int, std::allocator<int> > >]' wrap/test.cc:20: instantiated from here /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algobase.h:317: error: no matching function for call to 'std::__copy<true, std::random_access_iterator_tag>::copy(const int*&, const int*&, const int*&)'

Neal Becker wrote:
Thorsten Ottosen wrote:
Neal Becker wrote:
It's quite clear (to me) that this is an important use of the range concept.
I think the algorothm is wrong in this case. I would go for
template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, WriteForwardRange& );
template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, const WriteForwardRange& );
Did you mean something like this?
No. I meant that copy() should not take a "out-put range". You need a different algorithm for what you're doing. In particular, overwrite() can check bounds. -Thorsten

Thorsten Ottosen wrote:
Neal Becker wrote:
Thorsten Ottosen wrote:
Neal Becker wrote:
#include <boost/range.hpp> #include <vector>
template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {} What makes you think you can bind a temporary to an non-const reference (out)?
Yeah, same old problem. I think the c+ standard should be changed.
Well, && will help some.
It's quite clear (to me) that this is an important use of the range concept.
I think the algorothm is wrong in this case. I would go for
template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, WriteForwardRange& );
template< class SinglePassRange, class WritableForwardRange > void overwrite( const SinglePassRange&, const WriteForwardRange& );
If you don't want to write two overloads (or if you want to use a function that returns non-const-qualifed iterator_range). the "official" workaround maybe looks like... int main() { std::vector<int> out (2); copy (boost::make_iterator_range (out.begin(), out.begin()+2), boost::lambda::make_const(boost::make_iterator_range (out.begin(), out.begin()+2)) ); } -- Shunsuke Sogame

Neal Becker wrote:
#include <boost/range.hpp> #include <vector>
template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {}
int main() { std::vector<int> out (2); copy (boost::make_iterator_range (out.begin(), out.begin()+2), boost::make_iterator_range (out.begin(), out.begin()+2)); }
If make_iterator_range() returned a const-qualified iterator_range<>, this would work. Thorsten? -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Neal Becker wrote:
#include <boost/range.hpp> #include <vector>
template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {}
int main() { std::vector<int> out (2); copy (boost::make_iterator_range (out.begin(), out.begin()+2), boost::make_iterator_range (out.begin(), out.begin()+2)); }
If make_iterator_range() returned a const-qualified iterator_range<>, this would work. Thorsten?
Isn't the problem thet out is a reference? -Thorsten

Thorsten Ottosen wrote:
Eric Niebler wrote:
Neal Becker wrote:
#include <boost/range.hpp> #include <vector>
template<typename in_t, typename out_t> void copy (in_t const& in, out_t &out) {}
int main() { std::vector<int> out (2); copy (boost::make_iterator_range (out.begin(), out.begin()+2), boost::make_iterator_range (out.begin(), out.begin()+2)); }
If make_iterator_range() returned a const-qualified iterator_range<>, this would work. Thorsten?
Isn't the problem thet out is a reference?
out is a reference, which means that non-const rvalues will not bind to it. But const rvalues will because out_t will be deduced to be "iterator_range<> const". Try it and see. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Thorsten Ottosen wrote:
Eric Niebler wrote:
If make_iterator_range() returned a const-qualified iterator_range<>, this would work. Thorsten?
Isn't the problem thet out is a reference?
out is a reference, which means that non-const rvalues will not bind to it. But const rvalues will because out_t will be deduced to be "iterator_range<> const". Try it and see.
I see. I certainly didn't know that. I could get it to work on gcc, but not vc8. On what compilers does it actually work? -Thorsten

Thorsten Ottosen wrote:
Eric Niebler wrote:
Thorsten Ottosen wrote:
Eric Niebler wrote:
If make_iterator_range() returned a const-qualified iterator_range<>, this would work. Thorsten? Isn't the problem thet out is a reference?
out is a reference, which means that non-const rvalues will not bind to it. But const rvalues will because out_t will be deduced to be "iterator_range<> const". Try it and see.
I see. I certainly didn't know that. I could get it to work on gcc, but not vc8.
On what compilers does it actually work?
All of them, as far as I know. I just tried on VC8 and it worked: template<typename T> void foo(T &) {} struct empty {}; empty const bar() { empty e; return e; } int main() { foo(bar()); return 0; } Without thinking about this deeply, it seems that lightweight proxy objects such as iterator_range<> should always be returned as a const-qualified rvalues for precisely this reason. (Note that cv-qualifications on intrinsic return types are ignored, so "int foo()" and "int const foo()" are the same. Perhaps that's the problem you were seeing?) -- Eric Niebler Boost Consulting www.boost-consulting.com
participants (4)
-
Eric Niebler
-
Neal Becker
-
Shunsuke Sogame
-
Thorsten Ottosen