Почему const Type&& не приводится к Type&&?

Я знаю, что эти два квалификатора ортогональны, но это создает некоторые странные проблемы.

По сути, я пытался переместить и построить пару <const T, T> из других pair&& того же типа, но запутался, поскольку этот конструктор получился плохо сформированным :(

#include <iostream>

struct Special {
    int x = 0;
    explicit Special(int x): x(x) {}
    Special(const Special&) = delete;
    Special& operator=(const Special&) = delete;
    
    Special(Special&&) = default;
    Special& operator=(Special&&) = default;
};

struct NeitherDefaultNorCopyConstructible {
    Special x;

    NeitherDefaultNorCopyConstructible() = delete;
    NeitherDefaultNorCopyConstructible(const NeitherDefaultNorCopyConstructible&) = delete;
    NeitherDefaultNorCopyConstructible& operator=(const NeitherDefaultNorCopyConstructible&) = delete;

    NeitherDefaultNorCopyConstructible(Special&& x): x(std::move(x)) {}
    NeitherDefaultNorCopyConstructible(NeitherDefaultNorCopyConstructible&&) = default;
    NeitherDefaultNorCopyConstructible& operator=(NeitherDefaultNorCopyConstructible&&) = default;

    bool operator==(const NeitherDefaultNorCopyConstructible& other) const {
        return x.x == other.x.x;
    }
};

int main() {
    using NodeType = std::pair<const NeitherDefaultNorCopyConstructible, NeitherDefaultNorCopyConstructible>;
    NodeType a(Special(0), Special(1));
    NodeType b(std::move(a));
    return 0;
}

Сообщение об ошибке:

/usr/include/c++/11/bits/stl_pair.h:315:17: note: ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const NeitherDefaultNorCopyConstructible; _T2 = NeitherDefaultNorCopyConstructible]’ is implicitly deleted because the default definition would be ill-formed:
  315 |       constexpr pair(pair&&) = default;         ///< Move constructor

/home/bibaboba/CLionProjects/untitled4/main.cpp:32:28: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const NeitherDefaultNorCopyConstructible; _T2 = NeitherDefaultNorCopyConstructible]’
   32 |     NodeType b(std::move(a));

Действительно ли мне нужно растворить пару, чтобы переместить ее, или есть какой-то способ избежать этого?

Всегда публикуйте полную ошибку вместе с вашим вопросом.

user12002570 31.07.2024 17:36

Для воспроизведения проблемы не требуется пара, просто const NeitherDefaultNorCopyConstructibleДемо.

Jarod42 31.07.2024 17:37

И перемещение константного объекта приводит к копированию (если только не определен конструктор, принимающий (const Object&&) (но даже в этом случае внутренний не может ничего перемещать)).

Jarod42 31.07.2024 17:39

@Jarod42 ну, это не совсем проблема, я знаю, что все определено, и от перемещения "const T" я получаю "const T&&", но мы получаем необходимость растворить пару и привести ее элементы к константному виду. на самом деле переместите его, и проблема может распространиться на более сложные классы...

Riabov Vladimir 31.07.2024 17:44

«Почему const Type&& не приводит к Type&&?» потому что это отбросит квалификаторы CV, чего очень важно избегать. Если в вашем классе есть ctor, который принимает const Type&&, компилятор не будет делегировать копирование ctor. Делегирование происходит потому, что это лучший вариант вызова. Но в вашем случае копиктор тоже удаляется.

Chukwujiobi Canon 31.07.2024 17:50

Перемещение константы T дает const T&&, а выбранный конструктор - const T&, который удаляется. И "растворение" пары ничего не решает Демо...

Jarod42 31.07.2024 17:51
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

std::move — это просто приведение типов, возвращающее выражение xvalue. Ожидать, что он выкинет const, — это немного перебор.

std::move приведёт объект const Type к const Type&&. Это все, что он делает.

По сути, я пытался переместить и построить пару <const T, T> из других pair&& того же типа, но запутался, поскольку этот конструктор получился плохо сформированным.

Актер не пострадал. Вектора просто не существует, а тот, к которому прибегнул компилятор, был удален, поэтому компилятор застрял и решил выдать ошибки.

Вы можете либо предоставить const Type&& ctor (не лучшая моя рекомендация), либо отказаться от const перед std::move.

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

Mark Ransom 31.07.2024 18:12

да, но это также звучит болезненно, поскольку отбрасывание каждого константного квалификатора требует довольно больших усилий ради простого перемещения класса... причина, по которой я поместил константный квалификатор в член, заключалась во всем, кроме отключения движущегося квалификатора :( и простого перемещения затем пара расширяется до: NodeType b(std::move(const_cast<NeitherDefaultNorCopyConstructible&>(‌​a.first)), std::move(a.секунда)); хотелось бы, чтобы был способ сделать это быстрее и менее трудоемко; за строку кода

Riabov Vladimir 31.07.2024 18:18

@MarkRansom b вернет резюме.

Chukwujiobi Canon 31.07.2024 18:24

Извините, @RiabovVladimir, но перемещение переменной const — это красный флаг с самого начала.

Chukwujiobi Canon 31.07.2024 18:29

@ChukwujiobiCanon зависит от ситуации... у меня это узлы в unordered_map: ключ должен быть константным, поскольку его нельзя изменить, но в его перемещении не должно быть ничего плохого (единственное место, куда он перемещается, - это вставка нового взятого узла как пара по rvalue). тогда нет другого способа построить узел, кроме как переместить его, афаик...?

Riabov Vladimir 31.07.2024 18:35

Другие вопросы по теме