Первый пример, который принимает A по значению, делает два хода, а один по refref делает только один ход. В чем разница?
struct A
{
A() { cout << "constructor" << endl;}
A(const A&) { cout << "copy constructor " << endl;}
void operator=(const A&) { cout << "assignment operator" << endl; }
A( A&&) { cout << "move copy constructor" << endl;}
void operator=(A&&) { cout << "move assignment operator" << endl;}
};
struct C {
void func(A t) {
d.a = std::move(t);
}
struct Data {
A a;
};
Data d;
};
struct B {
void func(A t) {
C c;
c.func(std::move(t));
}
};
//////////////////////////////////////////////////////////
struct C {
template<class T>
void func(T&& t) {
d.a = std::forward<T>(t);
}
struct Data {
A a;
};
Data d;
};
struct B {
template<class T>
void func(T&& t) {
C c;
c.func(std::forward<T>(t));
}
};
От cppreference.com:
При использовании в соответствии со следующим рецептом в шаблоне функции,
перенаправляет аргумент в другую функцию точно так, как он был передан
вызывающая функция.template<typename T> wrapper(T&& arg) { foo(std::forward<T>(arg)); }
Так что в вашем фрагменте
struct B {
template<class T>
void func(T&& t) {
C c;
c.func(std::forward<T>(t));
}
};
std::foward<T>(t)
просто перешлю ваш T&&
Возражать c.func()
именно так B::func()
назывался. Это не требует перемещения, поэтому вы видите меньше ходов, используя std::forward<T>
,
Я действительно рекомендовал бы проверить сообщение в блоге Скотта Мейера на эту тему std::move
а также std::forward
: http://scottmeyers.blogspot.com/2012/11/on-superfluousness-of-stdmove.html
Других решений пока нет …