Копировать назначить карту, если элемент не может быть назначен

struct const_int { const int x = 1; };

int main(int argc, char **argv)
{
    std::unordered_map<int, const_int> map0;
    std::unordered_map<int, const_int> map1 { map0 }; // OK
    map1 = map0; // Compile-time error
    return 0;
}

Этот код работает в Visual C++ 2017, но завершается ошибкой с ошибкой компиляции в Visual C++ 2019:

14.23.27911\include\list(1210): error C2280: 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)': attempting to reference a deleted function
            with
            [
                _Kty=int,
                _Ty=const_int
            ]

Какая версия компилятора имеет правильную реализацию или поведение в этом случае не определено?

Ответ 1

Цитируя Билли Роберта О'Нила III из сообщества разработчиков Visual Studio, это не ошибка:

Это не ошибка. unordered_map является контейнером с распределителем, и операция назначения контейнеров с распределителем требует, чтобы value_type был назначаемым для копирования - см. containers.allocatoraware - а затем unord.req говорит, что для целей требований к неупорядоченным контейнерам вместо этого обращаются к key_type и mapped_type.

Это сработало в предыдущих выпусках Visual C++, потому что std::list, из которого построен std::unordered_map, использовался для освобождения всех узлов во время операции присваивания, поэтому, хотя было разрешено присваивать элементы, мы случайно не, Но это означало, что назначение 100 значений в список, уже содержащий 100 элементов, будет делать 200 ненужных вызовов для распределителя: освобождение всех 100 старых узлов, затем выделение 100 новых узлов. Изменение поведения, которое вы наблюдаете, связано с тем, что в VS2019 Update 2 мы реализовали оптимизацию для повторного использования уже выделенных узлов в назначении.

Ответ 2

В дополнение к ответу @MofX я хотел бы добавить сюда несколько ресурсов, в том числе и потому, что цитируемый текст содержит недействительные ссылки.

С [unord.map]/2 (выделено мной):

unordered_­map удовлетворяет всем требованиям контейнера, неупорядоченный ассоциативный контейнер и с учетом распределителя контейнер.

Это приводит к [container.requirements.general]/16, где для выражения присваивания в Таблице 86 требования (выделены мной):

Требуется: T является CopyInsertable для X и CopyAssignable.

Разумеется, тип, используемый в примере OP struct const_int { const int x = 1; };, не может быть назначен для копирования (из-за const и без пользовательского оператора присваивания), и поэтому компиляция не удалась.

Надеюсь, это прояснит ситуацию.

(Отказ от ответственности: Первоначально я был убежден, что MSVC имеет ошибку здесь, но я ошибся)