#include <iostream>
#include <memory>
struct copyableMovable
{
copyableMovable() { std::cout << "\tcopyableMovable()\t"; }
copyableMovable(const copyableMovable&) noexcept { std::cout << "\tcopyableMovable(const copyableMovable&)\n"; }
copyableMovable(copyableMovable&&) noexcept { std::cout << "\tcopyableMovable(copyableMovable&&)\n"; }
};
struct onlyMovable
{
onlyMovable() { std::cout << "\tonlyMovable()\t"; }
onlyMovable(onlyMovable&&) { std::cout << "\tonlyMovable(onlyMovable&&)\n"; }
onlyMovable(const onlyMovable&) = delete;
};
struct byValue
{
byValue(copyableMovable) { std::cout << "byValue(copyableMovable)\n"; }
byValue(onlyMovable) { std::cout << "byValue(onlyMovable)\n"; }
};
struct byReference
{
byReference(copyableMovable&) { std::cout << "byReference(copyableMovable&)\n"; }
byReference(onlyMovable&) { std::cout << "byReference(onlyMovable&)\n"; }
};
struct byConstReference
{
byConstReference(const copyableMovable&) { std::cout << "byConstReference(const copyableMovable&)\n"; }
byConstReference(const onlyMovable&) { std::cout << "byConstReference(const onlyMovable&)\n"; }
};
struct byRvalueReference
{
byRvalueReference(copyableMovable&&) { std::cout << "byRvalueReference(copyableMovable&&)\n"; }
byRvalueReference(onlyMovable&&) { std::cout << "byRvalueReference(onlyMovable&&)\n"; }
};
template <typename T, typename Arg>
std::unique_ptr<T> without_forward(Arg arg)
{ return std::unique_ptr<T>(new T(arg)); }
template <typename T, typename Arg>
std::unique_ptr<T> with_forward(Arg arg)
{ return std::unique_ptr<T>(new T(std::forward<Arg>(arg))); }
int main()
{
std::cout << "\tIDEA\nPassing lvalues and rvalues to function that return unique_ptr for them.\nWe have two kinds of objects:\n";
copyableMovable cm{}; std::cout << " - can be copied and moved along i. e. not restricted at all.\n";
onlyMovable om{}; std::cout << " - can be moved but cannot be copied, i. e. unique_ptr or streams etc.\n";
std::cout << "\n\n\n\tWITHOUT FORWARD\n";
std::cout << "BY VALUE\n";
std::cout << "Lvalue - copyable:\n"; auto val_copy_l = without_forward<byValue>(cm);
std::cout << "\nLvalue - moveable:\n"; //auto val_move_l = without_forward<byValue>(om);
std::cout << "Impossible, needs copy constructor.\n";
std::cout << "\nRvalue - copyable:\n"; auto val_copy_r = without_forward<byValue>(copyableMovable{});
std::cout << "\nRvalue - moveable:\n"; //auto val_move_r = without_forward<byValue>(onlyMovable{});
std::cout << "Impossible, needs copy constructor.\n\n";
std::cout << "BY REFERENCE\n";
std::cout << "Lvalue - copyable:\n"; auto ref_copy_l = without_forward<byReference>(cm);
std::cout << "\nLvalue - moveable:\n"; //auto ref_move_l = without_forward<byReference>(om);
std::cout << "Impossible, needs copy constructor\n";
std::cout << "\nRvalue - copyable:\n"; auto ref_copy_r = without_forward<byReference>(copyableMovable{});
std::cout << "\nRvalue - moveable:\n"; auto ref_move_r = without_forward<byReference>(onlyMovable{});
std::cout << "BY CONST REFERENCE\n";
std::cout << "\nLvalue - copyable:\n"; auto cref_copy_l = without_forward<byConstReference>(cm);
std::cout << "\nLvalue - moveable:\n"; //auto cref_move_l = without_forward<byConstReference>(om);
std::cout << "Impossible, needs copy constructor\n";
std::cout << "\nRvalue - copyable:\n"; auto cref_copy_r = without_forward<byConstReference>(copyableMovable{});
std::cout << "\nRvalue - moveable:\n"; auto cref_move_r = without_forward<byConstReference>(onlyMovable{});
std::cout << "BY RVALUE REFERENCE\n";
std::cout << "\nLvalue - copyable:\n"; //auto rref_copy_l = without_forward<byRvalueReference>(copyableMovable{});
std::cout << "Lvalue - moveable:\n"; //auto rref_move_l = without_forward<byRvalueReference>(onlyMovable{});
std::cout << "Rvalue - copyable:\n"; //auto rref_copy_r = without_forward<byRvalueReference>(copyableMovable{});
std::cout << "Rvalue - moveable:\n"; //auto rref_move_r = without_forward<byRvalueReference>(onlyMovable{});
std::cout << "Evarything impossible: they all need an rvalue, but receive an lvalue.\n";
std::cout << "\nWithout forward - short summary:\nPassing by value is impossible for onlyMovable."
"\nPassing by lvalue reference is impossible for onlyMovable rvalues."
"\nPassing by rvalue does not work at all.\n";
std::cout << "\n\n\n\tWITH FORWARD\n";
std::cout << "BY VALUE\n";
std::cout << "Lvalue - copyable:\n"; auto val_copy_lf = with_forward<byValue>(cm);
std::cout << "\nLvalue - moveable:\n"; //auto val_move_lf = with_forward<byValue>(om);
std::cout << "Impossible, needs copy constructor.\n";
std::cout << "\nRvalue - copyable:\n"; auto val_copy_rf = with_forward<byValue>(copyableMovable{});
std::cout << "\nRvalue - moveable:\n"; auto val_move_rf = with_forward<byValue>(onlyMovable{});
std::cout << "\nBY REFERENCE\n";
std::cout << "Lvalue - copyable:\n"; //auto ref_copy_lf = with_forward<byReference>(cm);
std::cout << "Lvalue - moveable:\n"; //auto ref_move_lf = with_forward<byReference>(om);
std::cout << "Rvalue - copyable:\n"; //auto ref_copy_rf = with_forward<byReference>(copyableMovable{});
std::cout << "Rvalue - moveable:\n"; //auto ref_move_rf = with_forward<byReference>(onlyMovable{});
std::cout << "All impossible - lvalue needed, not rvalue.\n";
std::cout << "\nBY CONST REFERENCE\n";
std::cout << "\nLvalue - copyable:\n"; auto cref_copy_lf = with_forward<byConstReference>(cm);
std::cout << "\nLvalue - moveable:\n"; //auto cref_move_lf = with_forward<byConstReference>(om);
std::cout << "Impossible, needs copy constructor\n";
std::cout << "\nRvalue - copyable:\n"; auto cref_copy_rf = with_forward<byConstReference>(copyableMovable{});
std::cout << "\nRvalue - moveable:\n"; auto cref_move_rf = with_forward<byConstReference>(onlyMovable{});
std::cout << "\nBY RVALUE REFERENCE\n";
std::cout << "\nLvalue - copyable:\n"; auto rref_copy_lf = with_forward<byRvalueReference>(copyableMovable{});
std::cout << "Lvalue - moveable:\n"; auto rref_move_lf = with_forward<byRvalueReference>(onlyMovable{});
std::cout << "Rvalue - copyable:\n"; auto rref_copy_rf = with_forward<byRvalueReference>(copyableMovable{});
std::cout << "Rvalue - moveable:\n"; auto rref_move_rf = with_forward<byRvalueReference>(onlyMovable{});
std::cout << "With forward - short summary:\nPassing by value is impossible for onlyMovable lvalue.\n"
"Passing by non const lvalue reference does not work at all.\n"
"Passing by const lvalue reference is impossible for onlyMovable lvalue.\n";
std::cout << "\n\nSUMMARY\nAfter enabling forward in function rerturning unique_ptr to it's argument:\n"
" - passing onlyMovable rvalue by value becomes possible\n"
" - passing lvalue copyableMovable and all rvalues by non const lvalue reference becomes impossible\n"
" - passing by const lvalue reference does not change\n"
" - passing by rvalue reference becomes possible for both lvalues and rvalues of both copyableMovable and onlyMovable\n"
"Experiment overlooks onlyCopyable type.\n";
}