Рассмотрим следующие классы.
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
случае вырождается в копию. Поведение Клана кажется довольно смешным: у меня есть совокупность с двумя подвижными членами, и все же моя совокупность - это неподвижный кирпич.
Кто прав?