Какова цель перегрузки const std:: begin и end?

Для std::begin у нас есть две перегрузки для контейнеров:

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

Но константа C может быть выведена с помощью обычных правил вычитания шаблона, поэтому кажется, что вторая перегрузка является избыточной. Что мне не хватает?

Ответы

Ответ 1

Разумно вызвать beginend, если на то пошло) на r-значение, если мы не используем результирующий итератор после уничтожения контейнера. Тем не менее, передача значения r параметру формы T& не будет работать, а именно, когда вступает в игру вторая перегрузка.

Однако вполне возможно, что мы имеем дело с бездумным преобразованием прежнего диапазона, основанного на формулировке предложения:

Добавить следующее в конец [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); } };

Когда стало ясно, что концепции не собираются превращать его в С++ 11, в статьи были внесены поправки, и все четыре функции temploids предположительно были переведены в эквивалентные шаблоны функций пространства имен. Это имело (потенциально непреднамеренное) последствие принятия rvalues, в то время как исходный код просто предназначался для различения между разными типами контейнеров.

Обратите внимание, что современная реализация begin/end будет использовать пересылку ссылок вместо этого - например.

template <typename T>
constexpr auto begin(T&& t)
  -> decltype(std::forward<T>(t).begin()) {
    return    std::forward<T>(t).begin();
}