В лекции о всеобщих ссылках Скотт Мейерс (примерно на 40-й минуте) сказал, что объекты, являющиеся универсальными ссылками, должны быть преобразованы в реальный тип, перед использованием. Другими словами, всякий раз, когда есть функция шаблона с универсальным ссылочным типом, перед использованием операторов и выражений следует использовать std::forward, иначе может быть сделана копия объекта.
Мое понимание этого в следующем примере:
#include <iostream>
struct A
{
  A() { std::cout<<"constr"<<std::endl; }
  A(const A&) { std::cout<<"copy constr"<<std::endl; }
  A(A&&) { std::cout<<"move constr"<<std::endl; }
  A& operator=(const A&) { std::cout<<"copy assign"<<std::endl; return *this; }
  A& operator=(A&&) { std::cout<<"move assign"<<std::endl; return *this; }
  ~A() { std::cout<<"destr"<<std::endl; }
  void bar()
  {
    std::cout<<"bar"<<std::endl;
  }
};
A getA()
{
  A a;
  return a;
}
template< typename T >
void callBar( T && a )
{
  std::forward< T >( a ).bar();
}
int main()
{
  {
    std::cout<<"\n1"<<std::endl;
    A a;
    callBar( a );
  }
  {
    std::cout<<"\n2"<<std::endl;
    callBar( getA() );
  }
}
Как и ожидалось, выход:
1
constr
bar
destr
2
constr
move constr
destr
bar
destr
Вопрос в том, почему это необходимо?
std::forward< T >( a ).bar();
Я пробовал без std:: forward, и кажется, что он работает нормально (выход такой же).
Точно так же, почему он рекомендует использовать перемещение внутри функции с rvalue? (ответ такой же, как и для std:: forward)
void callBar( A && a )
{
  std::move(a).bar();
}
Я понимаю, что как std::move, так и std::forward просто причисляются к соответствующим типам, но действительно ли эти броски нужны в приведенном выше примере?
Бонус: как можно изменить пример для создания копии объекта, который передается этой функции?