Допустимо ли помещать пользовательские предварительные условия в состояние цели перемещения в операторе назначения перемещения?
Да, но ...
В частности, было бы допустимо разрешить перемещение только к объекту, который не был полностью инициализирован ранее?
Конечно, но ...
Учтите:
Пока проблем нет, но ...
std::vector<Foo> foo;
// ...
Вы можете делать со своим классом все, что захотите, пока не будете использовать его со стандартным кодом (или чьим-либо другим кодом), который помещает Требования к вашему типу.
Например, стандарт гласит это о vector::erase
:
Для vector
и deque
, T
- это Cpp17MoveAssignable .
И Cpp17MoveAssignable определяется здесь .
t = rv
rv
состояние не указано. [ Примечание : rv
должен по-прежнему соответствовать требованиям библиотечного компонента, который его использует, независимо от того, относятся ли t
и rv
к одному и тому же объекту. Операции, перечисленные в этих требованиях, должны работать так, как указано, независимо от того, был ли перемещен rv
или нет. - конец примечания ]
Foo
не полностью соответствует требованиям Cpp17MoveAssignable. И это нормально, если вы не ожидаете, что Foo
будет работать с кодом, для которого требуется Cpp17MoveAssignable.
Отказ от ответственности: Будущий стандарт может ослабить требования к vector::erase
, чтобы разрешить Foo
. Но сегодня это не так.
Обратите внимание, что std::remove_if
также требует Cpp17MoveAssignable :
http://eel.is/c++draft/alg.remove#2
И эта небольшая модификация вашей программы на самом деле будет утверждать:
#include <algorithm>
#include <cassert>
#include <memory>
#include <vector>
struct Foo {
private:
std::unique_ptr<int> value;
public:
Foo(std::unique_ptr<int> value) : value{std::move(value)} {}
Foo(Foo&&) noexcept = default;
Foo &operator =(Foo&& other) noexcept {
assert(!value);
value = std::move(other.value);
return *this;
}
bool operator==(int i) const {return *value == i;}
};
int
main()
{
std::vector<Foo> foo;
foo.push_back(std::make_unique<int>(1));
foo.push_back(std::make_unique<int>(2));
foo.push_back(std::make_unique<int>(3));
std::remove_if(foo.begin(), foo.end(),
[](auto const& f) {return f == 1;});
}