I was trying out a program on universal references by applying std::move
and std::forward
on them. Until today I assumed that both were the same but in this very program (given below) the output amazed me.
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class X
{
string take="";
public:
template<class T>
void pass1 (T &&str) // str is a universal reference as it can bind to anything, both rvalue and lvalue references
{
take=move(str);
}
template<class T>
void pass2 (T &&str)
{
take=forward<T>(str);
}
void show()
{
cout<<"take = "<<take<<"\n";
}
}obj;
int main()
{
cout<<"using move on universal reference:-\n";
string str="he is there";
cout<<"str = "<<str<<'\n';
obj.pass1(str);
obj.show();
if (str.empty())
cout<<"str is empty\n\n";
else
cout<<"str isnt empty\n\n";
cout<<"using forward on universal reference:-\n";
str="he was there";
cout<<"str = "<<str<<'\n';
obj.pass2(str);
obj.show();
if (str.empty())
cout<<"str is empty\n\n";
else
cout<<"str isnt empty\n\n";
return 0;
}
Output:
using move on universal reference:-
str = he is there
take = he is there
str is empty
using forward on universal reference:-
str = he was there
take = he was there
str isnt empty
*/
My questions are:
move
and forward
work similarly? How are they working differently (in context with the above code)?Universal references mean that they can bind with apparently anything, both rvalues and lvalues. move
& forward
donot MOVE ANYTHING LITERALLY and rather perform casts ie they cast the argument to an rvalue
. The difference is that move
casts unconditionally whereas forward
will cast conditionally: it casts to an rvalue only if its argument was initialized with an rvalue. So move
always casts whereas forward
casts sometimes.
Hence the forward
in the above case doesn't empty the string as an lvalue (ie str)
was passed so it FORWARDED str
as an lvalue.