[Range] invalid initialization of non-const type with adaptors

Hi,
I was trying to compile the following simple piece of code:
#include ’
/usr/local/include/boost/range/algorithm/fill.hpp:29: error: in passing
argument 1 of ‘ForwardRange& boost::range::fill(ForwardRange&, const
Value&) [with ForwardRange =
boost::range_detail::reverse_range Am I missing something here?
Best regards,
Denis

On Mon, May 10, 2010 at 2:35 AM, Denis Taniguchi
Hi,
I was trying to compile the following simple piece of code:
#include
#include #include <vector>
int main(int argc, char *argv[]) { std::vector<int> vec(10); boost::fill(vec | boost::adaptors::reversed, 1);
return 0; }
But I get the following erros with gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3: Am I missing something here?
The reason this will not compile is that 'vec | boost::adaptors::reversed'
returns an unnamed temporary which is then attempted to be passed to the
fill function. On many versions of Visual C++ this actually will compile and
work as you intended due to a language extension, but this is non-standard.
This can't easily be remedied since the Range Concept is non-copyable, and
we obviously can't pass a const reference as the target to the fill
algorithm. Making the Range Concept cheaply copyable would mean that the
standard containers were no longer a model of the Range Concepts. I am
currently investigating extending the sub_range into some new Range concepts
that would integrate Alexandrescu's work into Boost.Range nicely. These
sub-ranges would have to be copyable with constant-time complexity and
therefore would enable the fill function to be written to take the sub-range
by value. This would make your code compile. This work, however is very much
in the experimental stage.
However this isn't a big problem because we typically solve the problem with
the current Boost.Range like this:
#include
Best regards,
Denis
Regards, Neil Groves

Neil Groves wrote:
This can't easily be remedied since the Range Concept is non-copyable, and we obviously can't pass a const reference as the target to the fill algorithm. Making the Range Concept cheaply copyable would mean that the standard containers were no longer a model of the Range Concepts. I am currently investigating extending the sub_range
It should be perfectly ok to make iterator_range and sub_range cheaply copyable, since they just wrap iterators. No need to extend the range concepts for that; iterator_range would simply provide more than those concepts.

On Mon, May 10, 2010 at 2:24 PM, Mathias Gaunard < mathias.gaunard@ens-lyon.org> wrote:
Neil Groves wrote:
This can't easily be remedied since the Range Concept is non-copyable, and
we obviously can't pass a const reference as the target to the fill algorithm. Making the Range Concept cheaply copyable would mean that the standard containers were no longer a model of the Range Concepts. I am currently investigating extending the sub_range
It should be perfectly ok to make iterator_range and sub_range cheaply copyable, since they just wrap iterators. No need to extend the range concepts for that; iterator_range would simply provide more than those concepts.
The rationale for providing new concepts that extend the sub_range is that we can then implement new containers and new algorithms in terms of concepts similar to those that Alexandrescu describes. As you have suggested this is actually a very simple extension to sub-range and allows efficient interoperability between iterator ranges and Alexandrescu style ranges. I'm finding this to be very nice when implementing ranges that do not map well to iterators, such as an unbounded integer range. I'm in the very early stages of exploring these ideas. Regards, Neil Groves

On Mon, 2010-05-10 at 15:35 +0100, Neil Groves wrote:
On Mon, May 10, 2010 at 2:24 PM, Mathias Gaunard
wrote: Neil Groves wrote: This can't easily be remedied since the Range Concept is non-copyable, and we obviously can't pass a const reference as the target to the fill algorithm. Making the Range Concept cheaply copyable would mean that the standard containers were no longer a model of the Range Concepts. I am currently investigating extending the sub_range
It should be perfectly ok to make iterator_range and sub_range cheaply copyable, since they just wrap iterators. No need to extend the range concepts for that; iterator_range would simply provide more than those concepts.
The rationale for providing new concepts that extend the sub_range is that we can then implement new containers and new algorithms in terms of concepts similar to those that Alexandrescu describes.
As you have suggested this is actually a very simple extension to sub-range and allows efficient interoperability between iterator ranges and Alexandrescu style ranges. I'm finding this to be very nice when implementing ranges that do not map well to iterators, such as an unbounded integer range.
I'm in the very early stages of exploring these ideas.
Looking forward to see it in next revisions of boost. Thank you all for the replies, and I'll try to post more meaningful examples next time. Regards
Regards, Neil Groves _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Neil Groves skrev:
On Mon, May 10, 2010 at 2:35 AM, Denis Taniguchi
mailto:taniguchi@tpn.usp.br> wrote: Hi,
I was trying to compile the following simple piece of code:
#include
#include #include <vector>
int main(int argc, char *argv[]) { std::vector<int> vec(10); boost::fill(vec | boost::adaptors::reversed, 1);
return 0; }
But I get the following erros with gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3: Am I missing something here?
We shall ignore that there is no reason to use "reversed" here.
The reason this will not compile is that 'vec | boost::adaptors::reversed' returns an unnamed temporary which is then attempted to be passed to the fill function. On many versions of Visual C++ this actually will compile and work as you intended due to a language extension, but this is non-standard.
Does make_reverse_range(rng) not use iterator_range rather than sub_range? Also, I don't see any reason why a const T& overload of boost::fill cannot exists as long as the const-iterator is actually a mutable iterator (like with iterator_range<MutableRange>). -Thorsten

Thorsten Ottosen skrev:
Also, I don't see any reason why a const T& overload of boost::fill cannot exists as long as the const-iterator is actually a mutable iterator (like with iterator_range<MutableRange>).
Also note that in a world with perfect forwarding, we shuold probably specify fill() like template< class Rng > void fill( Rng&& rng, range_value<Rng>::type x ); -Thorsten

On Mon, May 10, 2010 at 2:51 PM, Thorsten Ottosen
Thorsten Ottosen skrev:
Also, I don't see any reason why a const T& overload of boost::fill cannot
exists as long as the const-iterator is actually a mutable iterator (like with iterator_range<MutableRange>).
Also note that in a world with perfect forwarding, we shuold probably specify fill() like
template< class Rng > void fill( Rng&& rng, range_value<Rng>::type x );
Wouldn't this stop fill from working on ranges of abstract types? I like the idea of taking advantage of perfect forwarding where available.
-Thorsten
Regards, Neil Groves

Neil Groves skrev:
On Mon, May 10, 2010 at 2:51 PM, Thorsten Ottosen
mailto:nesotto@cs.aau.dk> wrote: Thorsten Ottosen skrev:
Also, I don't see any reason why a const T& overload of boost::fill cannot exists as long as the const-iterator is actually a mutable iterator (like with iterator_range<MutableRange>).
Also note that in a world with perfect forwarding, we shuold probably specify fill() like
template< class Rng > void fill( Rng&& rng, range_value<Rng>::type x );
Wouldn't this stop fill from working on ranges of abstract types?
I don't know. Usually when deal with abstract types, I don't use fill() for anything because those types are not copyable or assignable. -Thorsten

Also note that in a world with perfect forwarding, we shuold
probably specify fill() like
template< class Rng > void fill( Rng&& rng, range_value<Rng>::type x );
Wouldn't this stop fill from working on ranges of abstract types?
I don't know. Usually when deal with abstract types, I don't use fill() for anything because those types are not copyable or assignable.
-Thorsten
I have infrequently have abstract types that are assignable. I don't think this alters your key point about the forwarding but I think we should probably have this instead: template< class Range, class Value > void fill( Rng&& rng, const Value& x ); Where 'Value' is required to be convertible to one of the right-hand side arguments of an assignment to a range_value<Rng>::type. Does this look sensible to you? Regards, Neil Groves

Neil Groves skrev:
I have infrequently have abstract types that are assignable. I don't think this alters your key point about the forwarding but I think we should probably have this instead:
template< class Range, class Value > void fill( Rng&& rng, const Value& x );
Where 'Value' is required to be convertible to one of the right-hand side arguments of an assignment to a range_value<Rng>::type.
Does this look sensible to you?
I'm slightly against a template argument here as it means more code being generated. I would rather see the conversion to happen before the function is called. Would const typename range_value<Range>::type& not work? -Thorsten

AMDG Thorsten Ottosen wrote:
Neil Groves skrev:
I have infrequently have abstract types that are assignable. I don't think this alters your key point about the forwarding but I think we should probably have this instead:
template< class Range, class Value > void fill( Rng&& rng, const Value& x );
Where 'Value' is required to be convertible to one of the right-hand side arguments of an assignment to a range_value<Rng>::type.
Does this look sensible to you?
I'm slightly against a template argument here as it means more code being generated. I would rather see the conversion to happen before the function is called. Would
const typename range_value<Range>::type&
not work?
The standard has
template

Denis Taniguchi wrote:
Hi,
I was trying to compile the following simple piece of code:
#include
#include #include <vector>
int main(int argc, char *argv[]) { std::vector<int> vec(10); boost::fill(vec | boost::adaptors::reversed, 1);
return 0; }
Workaround suggestions: std::vector<int> vec(10); BOOST_AUTO(vec_reversed, vec | boost::adaptors::reversed); boost::fill(vec_reversed, 1); std::vector<int> vec(10); BOOST_FOREACH(int& i, vec | boost::adaptors::reversed) i = 1; The first one requires certain compilers.
participants (5)
-
Denis Taniguchi
-
Mathias Gaunard
-
Neil Groves
-
Steven Watanabe
-
Thorsten Ottosen