#include <iostream>
int func(){ return 0; }
struct Foo{};
struct Bar
{
Bar(){ std::cout << "default ctor" << std::endl; }
Bar(Bar const&){ std::cout << "copy ctor" << std::endl; }
Bar(Bar&&){ std::cout << "move ctor" << std::endl; }
Bar&operator=(Bar const&){ std::cout << "copy subst" << std::endl; return *this; }
Bar&operator=(Bar&&){ std::cout << "move subst" << std::endl; return *this; }
};
struct Baz
{
void f(Foo const&){ std::cout << "lvalue ref" << std::endl; }
void f(Foo&&) { std::cout << "rvalue ref" << std::endl; }
void g() & { std::cout << "lvalue overload" << std::endl; }
void g() && { std::cout << "rvalue overload" << std::endl; }
};
int main(int,char*[])
{
int x = 1;
Foo foo{};
x; // lvalue
1; // rvalue(prvalue)
func(); // rvalue(prvalue)
foo; // lvalue
Foo{}; // rvalue(prvalue)
// lvalue reference
int& lr1 = x;
// int& lr2 = 1; // ERROR
// const lvalue reference
int const& clr1 = x;
int const& clr2 = 1;
// rvalue reference
// int&& rr1 = x; // ERROR
int&& rr2 = 1;
// const rvalue reference
// int const&& crr1 = x; // ERROR
int const&& crr2 = 1;
// move
// int & lr3 = std::move(x); // ERROR
int && rr3 = std::move(x); // xrvalue
std::cout << "1: "; Bar b1{};
std::cout << "2: "; Bar b2(b1);
std::cout << "3: "; Bar b3(Bar{});
std::cout << "4: "; Bar b4(std::move(b3));
std::cout << "5: "; b1 = b2;
std::cout << "6: "; b1 = Bar{};
std::cout << "7: "; b1 = std::move(b4);
Baz baz;
baz.f(foo);
baz.f(Foo{});
baz.g();
Baz{}.g();
return 0;
}