Why does "std::begin()" always return "const_iterator" in such a case?

xmllmx
#include <vector>
#include <iostream>

using namespace std;

int main()
{
    vector<int> coll;

    decltype(std::begin(std::declval<vector<int>>()))
        pos_1 = coll.begin();
    auto pos_2 = coll.begin();

    cout << typeid(decltype(pos_1)).name() << endl;
    cout << typeid(decltype(pos_2)).name() << endl;
}

My compiler is clang 4.0. The output is:

class std::_Vector_const_iterator<class std::_Vector_val<struct std::_Simple_types<int> > >
class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<int> > >

That means: pos_1 = pos_2; is ok, while pos_2 = pos_1; is not ok.

Why does std::begin() always return const_iterator rather than iterator in such a case?

Piotr Skotnicki

The function call:

std::declval<std::vector<int>>()

results in an rvalue expression that can be denoted as:

std::vector<int>&&

The compiler has two (generic) overloads of std::begin to choose from ([iterator.range]):

template <class C> 
auto begin(C& c) -> decltype(c.begin());        // #1

template <class C> 
auto begin(const C& c) -> decltype(c.begin());  // #2

For an rvalue expression, only the second overload (#2) is viable -- an rvalue cannot be bound by a non-const lvalue reference. The const qualification of the referenced type implies that the compiler will use the const qualified overload of the begin member function:

const_iterator begin() const noexcept;
//                     ~~~~^

which returns an instance of type const_iterator.

You can change that behavior by requesting an lvalue expression of std::vector<int> from the std::declval call:

decltype(std::begin(std::declval<std::vector<int>&>())) pos_1 = coll.begin();
//                                             ~~^~~      

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Why does Scott Meyers recommend to prefer `iterator` to `const_iterator`

Why does std::set seem to force the use of a const_iterator?

Why const_iterator does not provide a base like reverse_iterator?

Is it specified in the C++11 standard that std::begin(Container&&) returns const_iterator?

How to remove code duplication const_iterator and iterator in my case?

Why were the std::vector::erase parameters changed to const_iterator?

Why is erasing via a const_iterator allowed in C++11?

Why const_iterator could be used with std::map::erase

Why doesn't const range based for use const_iterator?

Why moving a shared_ptr is allowed in a const_iterator?

Error C++ : ‘const_iterator’ does not name a type;

Why does std::cbegin return the same type as std::begin

Why can't I apply an iterator to a function which accepts a reference of const_iterator?

Why can't I call a template base class constructor with a const_iterator?

Why we don't have 'const iterator' in the C++ standard, but const_iterator?

How does using const_iterator result in the compilation of a more efficient program?

what does [] const_iterator::value_type in std::transform mean

Assigning a const_iterator to an iterator

Why always true conditional type in return does not type check in this case

Why std::begin uses trailing return type syntax?

Why does std::begin behave differently when called in a nested function

Why iterator vector::insert is not valid after filling: iterator insert (const_iterator position, size_type n, const value_type& val);

Iterator VS const_iterator, using it with distance()

find_if not working with const_iterator

Visual Studio const_iterator Assignment Error

map::const_iterator mapped type is not const

what is the difference between const_iterator and iterator?

Boost const_iterator to iterator conversion

Trouble implementing const_iterator in c++