Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / C++ Новый топик    Ответить
 Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7990
Всем привет!

Пишу шаблонный класс, в котором хочу определять его семантику копирования/перемещения в зависимости от типа шаблонного аргумента.

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

Это очень упрощенное описание реальной задачи, но его достаточно для обозначения проблемы.
В целом у меня все получается и работает как задумано, кроме одного момента (убрал все шаблонное, чтобы не усложнять).
struct copy_only // объекты данного класса можно только копировать
{
	copy_only(void) = default;
	copy_only(copy_only&&) noexcept = delete;
	copy_only& operator=(copy_only&&) noexcept = delete;
	copy_only(const copy_only& that) = default;
	copy_only& operator=(const copy_only& that) = default;
};

struct move_only // объекты данный класса можно только перемещать
{
	move_only(void) = default;
	move_only(const move_only& that) = delete;
	move_only(move_only&& that) noexcept = default;
	move_only& operator=(const move_only&) = delete;
	move_only& operator=(move_only&& that) noexcept = default;
};

// создадим на их основе производные классы, семантика которых будет определяться базовыми классами.
// если базовый класс умеет только копироваться, то и производный тоже можно только копировать, и наоборот

struct derived_from_move : move_only {};
struct derived_from_copy : copy_only {};

Проблема вот в чем:
int main()
{
	derived_from_move dmove;
	auto gc = dmove;		// ошибка: попытка обращения к delete функции в классе move_only - good!
	auto gm = std::move(dmove);	// ок

	derived_from_copy dcopy;
	auto xc = dcopy;		// ок
	auto xm = std::move(dcopy);	// ок (why!?) <- я хочу чтобы здесь была такая же ошибка как у класса derived_from_move

	copy_only co;
	auto cx = std::move(co);	// ошибка - good! хочу также
}

пощупать пример вживую

Если я буду использовать класс copy_only напрямую, без derived_from_copy, то поведение будет корректным с ожидаемой ошибкой.
Я знаю почему это происходит (с точки зрения move-семантики copy-only объекта), но мне бы хотелось реализовать это поведение, по аналогии с тем как работает тип copy_only или как derived_from_move.

Что посоветуете?

--------------------------------------------------------------
o(O_O)o
2 мар 21, 12:51    [22288292]     Ответить | Цитировать Сообщить модератору
 Re: Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6626
Cerebrum
	copy_only co;
	auto cx = std::move(co);	// ошибка - good! хочу также


То что тут ошибка вообще похоже на баг, потому что по логике если объект копируемый то его можно скопировать из какой угодно ссылки в т.ч. и rvalue.

Более того,
https://en.cppreference.com/w/cpp/language/overload_resolution

Defaulted move constructor and move assignment that are defined as deleted are never included in the list of candidate functions.

Inherited copy and move constructors are not included in the list of candidate functions when constructing a derived class object.

Из этих двух абзацев следует что как для derived_from_copy так и copy_only, move ctor исключается из списка кандидатов при поиске перегрузки, а значит он не может предовратить вызов copy ctor .

Кстати вот этот код работает без ошибки, а там тоже создается копия из rvalue ссылки :)
    copy_only func();
    auto cx = func();
2 мар 21, 18:29    [22288573]     Ответить | Цитировать Сообщить модератору
 Re: Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7990
Anatoly Moskovsky
То что тут ошибка вообще похоже на баг

проверял на двух компиляторах: clang и msvc - везде одинаково :)
2 мар 21, 20:28    [22288652]     Ответить | Цитировать Сообщить модератору
 Re: Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7990
судя по всему, это поведение by design и его никак не обойти
2 мар 21, 20:29    [22288653]     Ответить | Цитировать Сообщить модератору
 Re: Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
a guest
Member

Откуда:
Сообщений: 326
Anatoly Moskovsky
Cerebrum
	copy_only co;
	auto cx = std::move(co);	// ошибка - good! хочу также

То что тут ошибка вообще похоже на баг, потому что по логике если объект копируемый то его можно скопировать из какой угодно ссылки в т.ч. и rvalue.
Не существует никакого "копирования из ссылки". Не путай rvalue и rvalue reference.
Anatoly Moskovsky
Более того,
https://en.cppreference.com/w/cpp/language/overload_resolution

Defaulted move constructor and move assignment that are defined as deleted are never included in the list of candidate functions.

Inherited copy and move constructors are not included in the list of candidate functions when constructing a derived class object.

Из этих двух абзацев следует что как для derived_from_copy так и copy_only, move ctor исключается из списка кандидатов при поиске перегрузки
move-constructor у copy_only не defaulted. Так что первое предложение к copy_only не применимо. Оно применимо только к derived_from_copy.
А зачем сюда приплетено inherited copy/move constructors — это вообще непонятно. Вот что такое inherited constructors:
struct B {};
struct D : B {
    using B::B; // inherited constructors
};

Anatoly Moskovsky
Кстати вот этот код работает без ошибки, а там тоже создается копия из rvalue ссылки :)
    copy_only func();
    auto cx = func();
Если в случае std::move rvalue-ссылка есть хотя бы в возвращаемом типе, то в случае func() ссылок нет вообще нигде.
И до C++17 ошибка есть.
3 мар 21, 00:12    [22288741]     Ответить | Цитировать Сообщить модератору
 Re: Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6626
автор
Defaulted move constructor and move assignment that are defined as deleted are never included in the list of candidate functions.

a guest
move-constructor у copy_only не defaulted. Так что первое предложение к copy_only не применимо. Оно применимо только к derived_from_copy.

Тогда напишите что такое "Defaulted move constructor defined as deleted".
3 мар 21, 13:00    [22288988]     Ответить | Цитировать Сообщить модератору
 Re: Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
a guest
Member

Откуда:
Сообщений: 326
Anatoly Moskovsky
что такое "Defaulted move constructor defined as deleted".
Так сложно открыть предметный указатель в стандарте и найти там слово "defaulted"?
C++20 [dcl.fct.def.default]/5
Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions
Explicitly-defaulted это
C++20 [dcl.fct.def.default]/1
A function definition whose function-body is of the form
= default ;
is called an explicitly-defaulted definition.

Это
copy_only(copy_only&&) noexcept = delete;
explicitly-defaulted или implicitly-declared, чтобы быть defaulted?

Про то, когда defaulted defined as deleted можно почитать в [class.copy.ctor].
3 мар 21, 21:16    [22289285]     Ответить | Цитировать Сообщить модератору
 Re: Динамическое включение/отключение конструкторов/операторов присваивания в классе  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3634
Cerebrum, специализация шаблонов нынче не в фаворе?
28 мар 21, 05:01    [22300981]     Ответить | Цитировать Сообщить модератору
Все форумы / C++ Ответить