Подтвердить что ты не робот

Почему "std:: begin()" всегда возвращает "const_iterator" в таком случае?

#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;
}

Мой компилятор clang 4.0. Выход:

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

Это означает: pos_1 = pos_2; нормально, а pos_2 = pos_1; - не нормально.

Почему std::begin() всегда возвращает const_iterator, а не iterator в таком случае?

4b9b3361

Ответ 1

Вызов функции:

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

приводит к выражению rvalue, которое можно обозначить как:

std::vector<int>&&

Компилятор имеет две (общие) перегрузки std::begin для выбора ([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

Для выражения rvalue только вторая перегрузка (# 2) жизнеспособна - rvalue не может быть привязана ссылкой на константу lvalue. Константная квалификация ссылочного типа подразумевает, что компилятор будет использовать const-допустимую перегрузку функции-члена begin:

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

который возвращает экземпляр типа const_iterator.

Вы можете изменить это поведение, запросив выражение lvalue std::vector<int> из вызова std::declval:

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

Ответ 2

если у вас есть Type&& (временный), а затем - перегрузка предпочтет const Type& над Type&, так как временное соединение не привязывается к неконстантной lvalue-reference