Почему производный класс move конструктивен, когда базовый класс не является?
рассмотрим следующий пример:
#include <iostream>
#include <string>
#include <utility>
template <typename Base> struct Foo : public Base {
using Base::Base;
};
struct Bar {
Bar(const Bar&) { }
Bar(Bar&&) = delete;
};
int main() {
std::cout << std::is_move_constructible<Bar>::value << std::endl; // NO
std::cout << std::is_move_constructible<Foo<Bar>>::value << std::endl; // YES. Why?!
}
почему компилятор генерирует конструктор перемещения, несмотря на то, что базовый класс не является конструктивным?
это в стандарте или это ошибка компилятора? Можно ли" идеально распространять " конструкцию перемещения из базового в производный класс?
2 ответов
потому что:
конструктор перемещения по умолчанию, который определен как удаленный, игнорируется разрешением перегрузки.
([класс.copy] / 11)
Barконструктор перемещения -явно удалены, так что Bar не может быть перемещен. Но!--2-->конструктор перемещения -неявно удалены после того, как неявно объявлен как дефолт, из-за того, что Bar элемент не может быть перемещен. Поэтому Foo<Bar> может перемещается с помощью конструктора copy.
Edit: я также забыл упомянуть важный факт, что объявление наследующего конструктора, такое как using Base::Base не наследует конструкторы default, copy или move, поэтому Foo<Bar> не имеет явно удаленного конструктора перемещения, унаследованного от Bar.
1. Поведение std::is_move_constructible
это ожидаемое поведение std:: is_move_constructible:
типы без конструктора перемещения, но с конструктором копирования, который принимает
const T&аргументы, удовлетворитьstd::is_move_constructible.
что означает, что с конструктором копирования все еще можно построить T из ссылки rvalue T&&. И Foo<Bar> есть неявно объявленная копия конструктор.
2. Неявно объявленный конструктор перемещения Foo<Bar>
почему компилятор генерирует конструктор перемещения, несмотря на то, что базовый класс не является конструктивным?
фактически, конструктор перемещения Foo<Bar> определяется как удалены, но обратите внимание, что удаленный неявно объявленный конструктор перемещения игнорируется разрешением перегрузки.
в неявно объявленный или дефолтный конструктор перемещения для класса
Tis определено как удалено в любом из следующих значений true:... T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors); ...удаленный неявно объявленный конструктор перемещения игнорируется разрешением перегрузки (иначе это предотвратило бы инициализацию копирования из rvalue).
3. Различное поведение между Bar и Foo<Bar>
обратите внимание, что конструктор перемещения из Bar объявлен deleted явно и конструктор перемещения Foo<Bar> неявно объявлено и определено как deleted. Дело в том, что удаленный неявно объявленный конструктор перемещения игнорируется разрешением перегрузки, что позволяет перемещать конструкцию Foo<Bar> конструктор копирования. Но явно удаленный конструктор перемещения будет участвовать в разрешении перегрузки, означает при попытке переместить конструктор Bar будет выбран конструктор удаленного перемещения, затем программа плохо сформирована.
вот почему Foo<Bar> это перемещение конструктивно, но Bar нет.
стандарт имеет явное заявление об этом. 12.8$/11 копирование и перемещение объектов класса [класс.копировать]
конструктор перемещения по умолчанию, определенный как удаленный, игнорируется разрешением перегрузки ([over.матч], [конец.над.)] [ Примечание: в противном случае удаленный конструктор перемещения будет препятствовать инициализации из rvalue, который может использовать копии вместо конструктора. - конец Примечания ]