Ответ 1
Соответствующий стандартам компилятор будет "видеть" цикл for следующим образом:
auto&& __range = m;
for (auto __begin = std::begin(m), __end = std::end(m); __begin != __end; ++__begin) {
const std::pair<std::string, int>& p = *__begin;
//loop_statement
}
Что в основном сводит ваш вопрос к тому, почему разрешен следующий код:
std::pair<std::string, int> p = std::pair<const std::string, int>{};
Обратите внимание, что я опустил const&
часть p
, потому что это не актуально. Преобразование одно и то же, единственное различие заключается в том, что временная привязка к ссылке вместо копирования.
Если вам интересно, почему фрагмент OP не работает с неконстантной ссылкой, причиной является преобразование. Результатом преобразования является временный объект и потому, что любое изменение во временном случае будет бесполезным (его срок службы не расширяется и поэтому он сразу же уничтожается), поэтому язык запрещает его.
Это разрешено, потому что std::pair
имеет конструктор, который разрешает это преобразование.
template< class U1, class U2 >
pair( const pair<U1, U2>& p );
В вашем случае U1
выводится как const std::string
и U2
как int
. На самом деле не имеет значения, какие атрибуты cv U1
и U2
имеют, поскольку элементы p
копируются.
Преимущества одинаковы с тем, почему это разрешено:
const int zero{};
int zero2 = zero;
Например, рассмотрим следующий нереалистичный пример:
struct {
std::pair<int, int> pos;
} player;
std::pair<const int, const int> treasure{1, 2}; // position of treasure
player.pos = treasure; // ok
Теперь, если, как вы говорите, это обращение по какой-то причине было запрещено. Что программист должен был сделать?
player.pos.first = treasure.first;
player.pos.second = treasure.second;
Если это также будет запрещено, то и случай с нулями выше также не будет разрешен, что на самом деле не имеет смысла, потому что вы копируете zero
, поэтому не имеет значения, можете ли вы его изменить или нет, потому что это совершенно другая операция.
Если это разрешено, то почему бы player.pos = treasure;
быть запрещенным, потому что единственное, что он делает, это копирование? Как и выше, не имеет значения, можете ли вы изменить элементы treasure
, потому что вы только копируете их.
Также вы должны использовать auto&&
или const auto&
для диапазонов циклов (и, возможно, даже в целом?), потому что они могут избежать копирования, если вы не будете осторожны.