Рассмотрим следующие классы.
struct with_copy {
with_copy() = default;
with_copy(with_copy const&) {}
with_copy& operator=(with_copy const&) { return *this; }
};
struct foo {
with_copy c;
std::unique_ptr<int> p;
};
- Имеет ли
with_copyконструктор копирования? Да. Он был явно определен. - Есть ли
with_copyконструктор перемещения? Нет. Явный конструктор копирования предотвращает его создание. - Имеет ли
with_copyконструктор удаленных перемещений? Нет. Отсутствие конструктора перемещения не совпадает с удаленным. Конструктор с удаленным ходом попытается переместить плохо сформированный, а не дегенерировать на копию. - Скопирован ли
with_copy? Да. Его копия используется для копирования. - Является ли
with_copyподвижным? Да. Его конструктор копирования используется для перемещений.
... и теперь сложные.
- Имеет ли
fooконструктор копирования? Да. Он имеет удаленный, поскольку его определение по умолчанию будет плохо сформировано из-за вызоваunique_ptrконструктора удаленных копий. - Есть ли
fooконструктор перемещения? GCC говорит "да", clang говорит "нет" . - Имеет ли
fooконструктор удаленных перемещений? И GCC, и clang говорят "нет" . - Скопирован ли
foo? Нет. Конструктор его копии удален. - Является ли
fooподвижным? GCC говорит "да", clang говорит "нет" .
(Поведение аналогично, если рассматривать назначение вместо построения.)
Насколько я вижу, GCC верен. foo должен иметь конструктор перемещения, который выполняет перемещение по каждому элементу, который в with_copy случае вырождается в копию. Поведение Клана кажется довольно смешным: у меня есть совокупность с двумя подвижными членами, и все же моя совокупность - это неподвижный кирпич.
Кто прав?