#include <iostream>
#include <string>

std::string m_str;

void a(std::string&& other) 
{
	m_str = std::string(other); // this is wrong
	std::cout << "a: " << other << std::endl;
	// other is not EMPTY because inside the function,
	// the argument "other" got a name, and lost it's "rvalueness"
}

void b(std::string&& other)
{
	m_str = std::string(std::move(other));
	std::cout << "b: " << other << std::endl;
	// other is empty because std::move converted the lvalue "other" back to "rvalue"
}

void c(std::string&& other)
{
	m_str = std::string(std::forward<std::string>(other)); // other is empty as well.
	// because this function only accepts RValues, so std::forward does the same as std::move
	// if you call this function with a lvalue, you will get compile error.
	std::cout << "c: " << other << std::endl;
}

//This functions accepts both rvalues and lvalues (other is a "forwarding reference")
template<typename T>
void d(T&& other) 
{
	m_str = std::string(std::forward<T>(other)); //If you use move here, other will always be empty.
	std::cout << "d: " << other << std::endl;
	// If other was an rvalue, other will be empty.
	// If other was an lvalue, other will NOT be empty.
}

int main() 
{
	a(std::string("Hello World"));
	b(std::string("Hello World"));
	c(std::string("Hello World"));
	d(std::string("Hello World"));
	std::string lvalue = "Hello World";
	d(lvalue);
	return 0;
}