Почему мне нужно использовать std:: move в списке инициализации конструктора move?
предположим, у меня есть (тривиальный) класс, который является Move-constructible и move-assignable, но не copy-constructable или copy-assignable:
class movable
{
  public:
    explicit movable(int) {}
    movable(movable&&) {}
    movable& operator=(movable&&) { return *this; }
    movable(const movable&) = delete;
    movable& operator=(const movable&) = delete;
};
это прекрасно работает:
movable m1(movable(17));
это, конечно, не работает, потому что m1 не является rvalue:
movable m2(m1);
но, я могу обернуть m1 на std::move, который приводит его к ссылке rvalue, чтобы заставить его работать:
movable m2(std::move(m1));
пока все хорошо. Теперь, скажем, у меня есть (одинаково тривиальный) класс контейнера, который содержит одно значение:
template <typename T>
class container
{
  public:
    explicit container(T&& value) : value_(value) {}
  private:
    T value_;
};
это, однако, не работает:
container<movable> c(movable(17));
компилятор (я пробовал clang 4.0 и g++ 4.7.2) жалуется, что я пытаюсь использовать movableудалена копия-конструктор в containerсписок инициализации. Опять обертывание!--12--> на std::move делает его работы:
    explicit container(T&& value) : value_(std::move(value)) {}
но почему std::move необходимо в этом случае? Не value уже типа movable&&? Как value_(value) отличается от movable m1(movable(42))?
2 ответов
потому что value является именованной переменной и, следовательно, lvalue. The std::move требуется, чтобы вернуть его в rvalue, так что это вызовет перегрузку Move-constructor T в матче.
чтобы сказать это по-другому: ссылка rvalue может bind к rvalue, но это не само по себе rvalue. Это просто ссылка, и в выражении это lvalue. Единственный способ создать из него выражение, которое является rvalue, - это литье.
как
value_(value)отличается отmovable m1(movable(42))?
именованная ссылка rvalue является lvalue (и, таким образом, будет привязываться к удаленной копии ctor), в то время как временный, ну, rvalue (prvalue, чтобы быть конкретным).
§5 [expr] p6
[...] В общем, действие этого правила заключается в том, что именованные ссылки rvalue рассматриваются как lvalues, а неназванные ссылки rvalue на объекты рассматриваются как xvalues [...]
aswell как из примера:
A&& ar = static_cast<A&&>(a);
выражение
arявляется lvalue.
приведенные выше цитаты взяты из ненормативных Примечаний, но являются адекватным объяснением, так как остальная часть пункта 5 идет и объясняет, какие выражения только создать xvalues† (ака, только указанные выражения и никто другой не будет создавать xvalues). См. также здесь исчерпывающий перечень.
† xvalues одна подгруппа rvalues, при этом prvalues является другой подгруппой. См.этот вопрос для объяснений.