Заставить компилятор выдать ошибку при перемещении конструктора, не определенного с помощью ctor удаленной копии базового класса

Рассмотрим базовый класс, который предотвращает создание копий и присваивание копий следующим образом:

class NonCopyable {
    public:
        NonCopyable() = default;
        ~NonCopyable() = default;

        NonCopyable(NonCopyable const&)                 = delete;
        NonCopyable& operator=(NonCopyable const&)      = delete;
};

Наши разработчики теперь могут включить этот класс и использовать его для отключения копирования для унаследованных классов, например:

class CopyTest : public NonCopyable {
    public:
        CopyTest() {
            std::cout << "copy test created" << std::endl;
        }

        ~CopyTest() {
            std::cout << "copy test deleted" << std::endl;
        }
};

Когда я пытаюсь использовать класс CopyTest:

CopyTest ct, ct1(ct);

or

CopyTest ct;
CopyTest ct1 = ct2;

Компилятор выдает ошибку: use of deleted function xxx (где xxx - мой удаленный ctor копии или оператор копирования)

Затем, если я хочу std::move объект CopyTest:

CopyTest ct;
CopyTest ct1 = std::move(ct);

Компилятор выдает ту же ошибку (использование удаленной функции xxx - где xxx остается моим оператором копирования или оператором присваивания).

Если я правильно напомню, это потому, что разработчик не определил правильный оператор перемещения / присваивания.

Можно ли заставить компилятор сообщить разработчику класса CopyTest, что ошибка перемещения здесь, потому что он не определил правильный оператор перемещения / присваивания, а не потому, что оператор копирования / присваивания удален из базовый класс?

Платформа :

Debian 9

GCC 6.3.0

Флаги компиляции:

-fpermissive -ggdb -std = c ++ 11


person Ayak973    schedule 12.12.2018    source источник
comment
Любой хороший разработчик знает, что вероятной причиной этой ошибки является отсутствие конструктора перемещения (в конце концов, он использует std::move). Я бы не стал об этом беспокоиться.   -  person Cássio Renan    schedule 12.12.2018
comment
Я согласен с вами, но я не хочу полагаться на других людей или свои вероятные навыки, и подумал, что точную ошибку компилятора легче понять новичкам, таким как я ...   -  person Ayak973    schedule 12.12.2018
comment
Ошибка компилятора точная: неявно определенный конструктор перемещения удаляется, потому что ctor копирования есть.   -  person Walter    schedule 13.12.2018


Ответы (2)


добавлять

    NonCopyable(NonCopyable &&)                 = delete;
    NonCopyable& operator=(NonCopyable &&)      = delete;

который теперь жалуется на удаление ctor перемещения базового класса.

person Yakk - Adam Nevraumont    schedule 12.12.2018
comment
Цель здесь - узнать, может ли компилятор жаловаться на отсутствие ctor перемещения дочернего класса, а не на удаленный ctor перемещения базового класса? - person Ayak973; 13.12.2018
comment
@ Ayak973 Дочерний класс получает написанный для него объект перемещения, который не работает потому что у базового класса есть удаленный объект перемещения. Компилятор сообщает, почему объект перемещения производного класса не может быть написан за вас. - person Yakk - Adam Nevraumont; 13.12.2018
comment
Мое рассуждение было необъективным, теперь я лучше понимаю с вашим комментарием - person Ayak973; 13.12.2018

Формально говоря, неявно сгенерированный объект / назначение перемещения определяется как «удаленный» в самом базовом классе NonCopyable. «Удаленный» объект / назначение перемещения просто игнорируется разрешением перегрузки (вместо того, чтобы быть удаленным в строгом смысле). Поскольку NonCopyable не копируется и не перемещается, для любого подкласса неявные (и = по умолчанию) операции копирования и перемещения будут определены как удаленные.

В строгом соответствии со стандартом iso C ++ ваш дизайн имеет желаемую семантику, но, к сожалению, большинство компиляторов не обеспечивают строгое соблюдение так называемого правила пяти, а только обеспечивают соблюдение подмножества неявно удаленных правило. Например, если пользователь объявил деструктор для класса, это означает, что неявные (и = по умолчанию) определения всех операций копирования и перемещения будут удалены, но я не знаю компилятора, который не может скомпилировать или выдать предупреждение, когда неявно объявленный конструктор копирования будет ODR, используемым для такого класса.

Я наткнулся на этот отчет об ошибке https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58407#c16. Это предполагает, что компиляторы, вероятно, начнут применять или предупреждать о нарушениях правила пяти.

person Julien Villemure-Fréchette    schedule 13.12.2018
comment
Однако «Правило пяти» не является правилом языка. - person Deduplicator; 13.12.2018
comment
@Deduplicator Я знаю, это скорее рекомендация, но я использовал ее как ярлык. - person Julien Villemure-Fréchette; 13.12.2018