Должен ли я использовать std:: move или std:: forward в операциях move ctors/assign?

Если я ошибаюсь, кажется, что все работает просто отлично - есть ли лучшая практика, чтобы предпочесть один над другим?

Пример:

struct A
{
    A(){}
    A(const A&){ std::cout << "A(const A&)\n"; }
    A(A&&){ std::cout << "A(A&&)\n"; }
};

struct B
{
    B(){}
    B(const B& right) : x(right.x){ std::cout << "B(const B&)\n"; }
    B(B&& right) : x(std::forward<A>(right.x)){ std::cout << "B(B&&)\n"; }

    A x;
};

struct C
{
    C(){}
    C(const C& right) : x(right.x){ std::cout << "C(const C&)\n"; }
    C(C&& right) : x(std::move(right.x)){ std::cout << "C(C&&)\n"; }

    A x;
};

struct D
{
    D(){}
    D(const D& right) : x(right.x){ std::cout << "D(const D&)\n"; }
    D(D&& right) : x(right.x){ std::cout << "D(D&&)\n"; }

    A x;
};

int main()
{
    std::cout << "--- B Test ---\n";
    B b1;
    B b2(std::move(b1));
    std::cout << "--- C Test ---\n";
    C c1;
    C c2(std::move(c1));
    std::cout << "--- D Test ---\n";
    D d1;
    D d2(std::move(d1));
}

Вывод:

--- B Test ---
A(A&&)
B(B&&)
--- C Test ---
A(A&&)
C(C&&)
--- D Test ---
A(const A&)
D(D&&)

Ответ 1

Возникает вопрос: действительно ли это оператор конструктора/назначения перемещения для класса? Или они только выглядят так краем глаза?

struct X{
  X(X&&); // move ctor #1

  template<class T>
  X(T&&); // perfect forwarding ctor #2

  X& operator=(X&&); // move assignment operator #3

  template<class T>
  X& operator=(T&&); // perfect forwarding ass. operator #4
};

В реальном движении ctor (# 1) и операторе присваивания перемещения (# 3) вы никогда не будете использовать std::forward, так как, как вы правильно оценили, вы всегда будете двигаться.

Обратите внимание, что std::forward никогда не имеет смысла без идеального шаблона пересылки (T&&). Это как раз для # 2 и # 4. Здесь вы никогда не будете использовать std::move, так как вы не знаете, действительно ли вы получили rvalue (A-OK) или lvalue (не так много).

См. этот мой ответ для объяснения того, как работает std::forward.