I understand the first code will respect the lvalue or rvalue type of the arg (doing perfect forwarding), but why would we care the parameter remains lvalue or rvalue??
what is a real world example where we care the parameter's value category is important?
This only matters if do_print might handle rvalue arguments differently (e.g. more efficiently) than lvalue arguments. If you know that do_print always takes its argument by const ref then there is no point in using std::forward here.
These functions use perfect forwarding, to forward the arguments to the constructors.
For example, if the object that is being constructed is a std::vector<int> and you pass a temporary std::vector<int> object as argument to the function, then perfect forwarding allows the temporary object to be "moved" by the constructor.
Thanks to perfect forwarding, this calls the move constructor rather than the copy constructor, so there is no copying of the vector elements in the above example.