Я знаю, что эти два квалификатора ортогональны, но это создает некоторые странные проблемы.
По сути, я пытался переместить и построить пару <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));
Действительно ли мне нужно растворить пару, чтобы переместить ее, или есть какой-то способ избежать этого?
Для воспроизведения проблемы не требуется пара, просто const NeitherDefaultNorCopyConstructible
Демо.
И перемещение константного объекта приводит к копированию (если только не определен конструктор, принимающий (const Object&&)
(но даже в этом случае внутренний не может ничего перемещать)).
@Jarod42 ну, это не совсем проблема, я знаю, что все определено, и от перемещения "const T" я получаю "const T&&", но мы получаем необходимость растворить пару и привести ее элементы к константному виду. на самом деле переместите его, и проблема может распространиться на более сложные классы...
«Почему const Type&&
не приводит к Type&&
?» потому что это отбросит квалификаторы CV, чего очень важно избегать. Если в вашем классе есть ctor, который принимает const Type&&
, компилятор не будет делегировать копирование ctor. Делегирование происходит потому, что это лучший вариант вызова. Но в вашем случае копиктор тоже удаляется.
Перемещение константы T дает const T&&
, а выбранный конструктор - const T&
, который удаляется. И "растворение" пары ничего не решает Демо...
std::move
— это просто приведение типов, возвращающее выражение xvalue
. Ожидать, что он выкинет const
, — это немного перебор.
std::move
приведёт объект const Type
к const Type&&
. Это все, что он делает.
По сути, я пытался переместить и построить пару
<const T, T>
из другихpair&&
того же типа, но запутался, поскольку этот конструктор получился плохо сформированным.
Актер не пострадал. Вектора просто не существует, а тот, к которому прибегнул компилятор, был удален, поэтому компилятор застрял и решил выдать ошибки.
Вы можете либо предоставить const Type&&
ctor (не лучшая моя рекомендация), либо отказаться от const перед std::move
.
Отказ от const порождает ряд проблем, не последней из которых является неопределенное поведение.
да, но это также звучит болезненно, поскольку отбрасывание каждого константного квалификатора требует довольно больших усилий ради простого перемещения класса... причина, по которой я поместил константный квалификатор в член, заключалась во всем, кроме отключения движущегося квалификатора :( и простого перемещения затем пара расширяется до: NodeType b(std::move(const_cast<NeitherDefaultNorCopyConstructible&>(a.first)), std::move(a.секунда)); хотелось бы, чтобы был способ сделать это быстрее и менее трудоемко; за строку кода
@MarkRansom b
вернет резюме.
Извините, @RiabovVladimir, но перемещение переменной const
— это красный флаг с самого начала.
@ChukwujiobiCanon зависит от ситуации... у меня это узлы в unordered_map: ключ должен быть константным, поскольку его нельзя изменить, но в его перемещении не должно быть ничего плохого (единственное место, куда он перемещается, - это вставка нового взятого узла как пара по rvalue). тогда нет другого способа построить узел, кроме как переместить его, афаик...?
Всегда публикуйте полную ошибку вместе с вашим вопросом.