For std::begin
, we have two overloads for containers:
template< class C >
auto begin( C& c ) -> decltype(c.begin());
template< class C >
auto begin( const C& c ) -> decltype(c.begin());
But the constness of C
can be deduced by the usual template deduction rules, so it seems like the second overload is redundant. What am I missing?
std::beginReturns an iterator to the beginning of the given container c or array array . 1) Returns a possibly const-qualified iterator to the beginning of the container c . 2) Returns a pointer to the beginning of the array array .
begin() returns an iterator to beginning while cbegin() returns a const_iterator to beginning. The basic difference between these two is iterator (i.e begin() ) lets you change the value of the object it is pointing to and const_iterator will not let you change the value of the object.
A const iterator points to an element of constant type which means the element which is being pointed to by a const_iterator can't be modified. Though we can still update the iterator (i.e., the iterator can be incremented or decremented but the element it points to can not be changed).
begin() function is used to return an iterator pointing to the first element of the vector container. begin() function returns a bidirectional iterator to the first element of the container.
It's reasonable to call begin
(and end
, for that matter) on an rvalue, provided we don't use the resulting iterator after the container has been destroyed. However, passing an rvalue to a parameter of the form T&
will not work, which is where the second overload comes into play.
However, it may well be that we're dealing with a thoughtless transformation of a former range-based for proposal wording:
Add the following to the end of [container.concepts.member]:
template<Container C> concept_map Range<C> { typedef C::iterator iterator; iterator begin( C& c ) { return Container<C>::begin(c); } iterator end( C& c ) { return Container<C>::end(c); } }; template<Container C> concept_map Range<const C> { typedef C::const_iterator iterator; iterator begin( const C& c ) { return Container<C>::begin(c); } iterator end( const C& c ) { return Container<C>::end(c); } };
When it became clear that concepts weren't going to make it into C++11, papers were amended, and all four function temploids were presumably translated into equivalent namespace-scope function templates. This had the (potentially unintended) consequence of rvalues being accepted, while the original code was simply intended to distinguish between differently qualified container types.
Note that a modern implementation of begin
/end
would use forwarding references instead - e.g.
template <typename T>
constexpr auto begin(T&& t)
-> decltype(std::forward<T>(t).begin()) {
return std::forward<T>(t).begin();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With