Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of the const overloads of std::begin and std::end?

Tags:

c++

c++11

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?

like image 409
Desert Fish Avatar asked Nov 07 '15 18:11

Desert Fish


People also ask

What is std:: begin?

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 .

What is the difference between Begin and Cbegin?

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.

What is const iterator in C++?

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).

What is begin function in C?

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.


1 Answers

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();
}
like image 170
Columbo Avatar answered Sep 26 '22 00:09

Columbo