// File: onlyuser[P]Sandbox/test_c/c++14/main.cpp
// Function: main
int main(int argc, char** argv)
{
    // NOTE: won't compile
    //std::cout << "\ntest0" << std::endl;
    //{
    //    f0(g()); // rvalue won't bind to "A&"
    //}

    std::cout << "\ntest1" << std::endl;
    {
        f(the_a); // lvalue reference prefers "A&"
        f(g());   // rvalue reference links to "const A&", but not "A&" (why write to a temporary? that's what rvalue ref is for!)
    }

    std::cout << "\ntest2" << std::endl;
    {
        f2(the_a); // lvalue reference prefers "A&"
        f2(g());   // rvalue reference prefers "A&&" over "const A&"
    }

    std::cout << "\ntest3" << std::endl;
    {
        f2_forward(the_a); // preserves rvalueness despite rvalue collapse rule (T& + T&& ==> T&)
        f2_forward(g());   // preserves rvalueness despite rvalue collapse rule (T& + T&& ==> T&)
    }

    std::cout << "\ntest4" << std::endl;
    {
        std::shared_ptr<::A> shared_a = std::make_shared<::A>("outer");

        std::cout << "ENTER SCOPE" << std::endl;
        {
            auto unique_a = std::make_unique<::A>("inner");
            shared_a = std::move(unique_a); // exchanges ownership with outer
        }
        std::cout << "LEAVE SCOPE" << std::endl;
    }

    std::cout << "\ntest5" << std::endl;
    {
        ::A a1("outer");

        std::cout << "ENTER SCOPE" << std::endl;
        {
            ::A a2("inner");
            std::swap(a1, a2); // swap works as you'd expect; exchanges ownership with outer
        }
        std::cout << "LEAVE SCOPE" << std::endl;
    }

    std::cout << "\ntest6" << std::endl;
    {
        A(A(A("hello world"))); // anonymous construction of object of type A; RVO is default behavior unless use gcc switch -fno-elide-constructors
    }

    std::cout << "\ntest7" << std::endl;
    {
        A(A(A(), 0), 0); // anonymous construction of object of type A; RVO not possible because "A(A(A()))" pattern is broken
    }

    std::cout << "\ntest8" << std::endl;
    {
        {
            A(A(A())); // center A is local variable declaration of function pointer type
            std::cout << typeid(A).name() << std::endl; // A (A (*)())
        }

        {
            typedef A(A(A())); // center A is function pointer type
            std::cout << typeid(A).name() << std::endl; // A (A (*)())
        }
    }

    std::cout << "\ntest9" << std::endl;
    {
        std::vector<::A> v;
        v.emplace_back("hello world"); // emplace is unrelated to rvalue reference
    }

    std::cout << "\ntest10" << std::endl;
    {
        std::shared_ptr<A> a = std::make_shared<A>("hello world"); // std::make_shared is unrelated to rvalue reference
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x130, %rsp            # imm = 0x130
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq 0x7b78(%rip), %rdi      # 0x9fd8
leaq 0x3bea(%rip), %rsi      # 0x6051
callq 0x20b0
movq %rax, %rdi
movq 0x7b4a(%rip), %rsi      # 0x9fc0
callq 0x20e0
leaq 0x7c4e(%rip), %rdi      # 0xa0d0
callq 0x22d0
leaq -0x18(%rbp), %rdi
movq %rdi, -0xb0(%rbp)
callq 0x2410
movq -0xb0(%rbp), %rdi
callq 0x2310
jmp 0x24a5
leaq -0x18(%rbp), %rdi
callq 0x2a70
movq 0x7b23(%rip), %rdi      # 0x9fd8
leaq 0x3b9c(%rip), %rsi      # 0x6058
callq 0x20b0
movq %rax, %rdi
movq 0x7af5(%rip), %rsi      # 0x9fc0
callq 0x20e0
leaq 0x7bf9(%rip), %rdi      # 0xa0d0
callq 0x2350
leaq -0x30(%rbp), %rdi
movq %rdi, -0xb8(%rbp)
callq 0x2410
movq -0xb8(%rbp), %rdi
callq 0x23d0
jmp 0x24fa
leaq -0x30(%rbp), %rdi
callq 0x2a70
movq 0x7ace(%rip), %rdi      # 0x9fd8
leaq 0x3b4e(%rip), %rsi      # 0x605f
callq 0x20b0
movq %rax, %rdi
movq 0x7aa0(%rip), %rsi      # 0x9fc0
callq 0x20e0
leaq 0x7ba4(%rip), %rdi      # 0xa0d0
callq 0x2bb0
leaq -0x38(%rbp), %rdi
movq %rdi, -0xc0(%rbp)
callq 0x2410
movq -0xc0(%rbp), %rdi
callq 0x2bd0
jmp 0x254f
leaq -0x38(%rbp), %rdi
callq 0x2a70
movq 0x7a79(%rip), %rdi      # 0x9fd8
movq %rdi, -0xd0(%rbp)
leaq 0x3af9(%rip), %rsi      # 0x6066
callq 0x20b0
movq %rax, %rdi
movq 0x7a44(%rip), %rsi      # 0x9fc0
callq 0x20e0
leaq 0x3ae5(%rip), %rsi      # 0x606d
leaq -0x48(%rbp), %rdi
callq 0x2bf0
movq -0xd0(%rbp), %rdi
leaq 0x3ad4(%rip), %rsi      # 0x6073
callq 0x20b0
movq %rax, -0xc8(%rbp)
jmp 0x25ad
movq -0xc8(%rbp), %rdi
movq 0x7a05(%rip), %rsi      # 0x9fc0
callq 0x20e0
jmp 0x25c2
leaq 0x3ab6(%rip), %rsi      # 0x607f
leaq -0x50(%rbp), %rdi
callq 0x2c60
jmp 0x25d4
leaq -0x48(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x2ce0
jmp 0x25e3
leaq -0x50(%rbp), %rdi
callq 0x2d10
movq 0x79e5(%rip), %rdi      # 0x9fd8
leaq 0x3a8b(%rip), %rsi      # 0x6085
callq 0x20b0
movq %rax, -0xd8(%rbp)
jmp 0x2608
movq -0xd8(%rbp), %rdi
movq 0x79aa(%rip), %rsi      # 0x9fc0
callq 0x20e0
jmp 0x261d
leaq -0x48(%rbp), %rdi
callq 0x2d70
movq 0x79ab(%rip), %rdi      # 0x9fd8
movq %rdi, -0xe8(%rbp)
leaq 0x3a56(%rip), %rsi      # 0x6091
callq 0x20b0
movq %rax, %rdi
movq 0x7976(%rip), %rsi      # 0x9fc0
callq 0x20e0
leaq 0x3a17(%rip), %rsi      # 0x606d
leaq -0x58(%rbp), %rdi
callq 0x29e0
movq -0xe8(%rbp), %rdi
leaq 0x3a06(%rip), %rsi      # 0x6073
callq 0x20b0
movq %rax, -0xe0(%rbp)
jmp 0x267b
movq -0xe0(%rbp), %rdi
movq 0x7937(%rip), %rsi      # 0x9fc0
callq 0x20e0
jmp 0x2690
leaq 0x39e8(%rip), %rsi      # 0x607f
leaq -0x60(%rbp), %rdi
callq 0x29e0
jmp 0x26a2
leaq -0x58(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0x2d90
jmp 0x26b1
leaq -0x60(%rbp), %rdi
callq 0x2a70
movq 0x7917(%rip), %rdi      # 0x9fd8
leaq 0x39bd(%rip), %rsi      # 0x6085
callq 0x20b0
movq %rax, -0xf0(%rbp)
jmp 0x26d6
movq -0xf0(%rbp), %rdi
movq 0x78dc(%rip), %rsi      # 0x9fc0
callq 0x20e0
jmp 0x26eb
leaq -0x58(%rbp), %rdi
callq 0x2a70
movq 0x78dd(%rip), %rdi      # 0x9fd8
movq %rdi, -0x108(%rbp)
leaq 0x398f(%rip), %rsi      # 0x6098
callq 0x20b0
movq %rax, %rdi
movq 0x78a8(%rip), %rsi      # 0x9fc0
movq %rsi, -0x100(%rbp)
callq 0x20e0
leaq 0x3974(%rip), %rsi      # 0x609f
leaq -0x68(%rbp), %rdi
movq %rdi, -0x110(%rbp)
callq 0x29e0
movq -0x110(%rbp), %rdi
callq 0x2a70
movq -0x108(%rbp), %rdi
leaq 0x3956(%rip), %rsi      # 0x60ab
callq 0x20b0
movq -0x100(%rbp), %rsi
movq %rax, %rdi
callq 0x20e0
leaq -0x80(%rbp), %rdi
movq %rdi, -0xf8(%rbp)
callq 0x2e00
movq -0xf8(%rbp), %rsi
leaq -0x78(%rbp), %rdi
xorl %edx, %edx
callq 0x2e60
jmp 0x278d
leaq -0x70(%rbp), %rdi
leaq -0x78(%rbp), %rsi
xorl %edx, %edx
callq 0x2e60
jmp 0x279e
leaq -0x70(%rbp), %rdi
callq 0x2a70
leaq -0x78(%rbp), %rdi
callq 0x2a70
leaq -0x80(%rbp), %rdi
callq 0x2a70
movq 0x7818(%rip), %rdi      # 0x9fd8
movq %rdi, -0x128(%rbp)
leaq 0x38e4(%rip), %rsi      # 0x60b2
callq 0x20b0
movq %rax, %rdi
movq 0x77e3(%rip), %rsi      # 0x9fc0
movq %rsi, -0x120(%rbp)
callq 0x20e0
leaq 0x7488(%rip), %rdi      # 0x9c78
movq %rdi, -0x130(%rbp)
callq 0x2ec0
movq -0x128(%rbp), %rdi
movq %rax, %rsi
callq 0x20b0
movq -0x120(%rbp), %rsi
movq %rax, %rdi
callq 0x20e0
movq -0x130(%rbp), %rdi
callq 0x2ec0
movq -0x128(%rbp), %rdi
movq %rax, %rsi
callq 0x20b0
movq -0x120(%rbp), %rsi
movq %rax, %rdi
callq 0x20e0
movq -0x128(%rbp), %rdi
leaq 0x3867(%rip), %rsi      # 0x60b9
callq 0x20b0
movq -0x120(%rbp), %rsi
movq %rax, %rdi
callq 0x20e0
leaq -0x98(%rbp), %rdi
movq %rdi, -0x118(%rbp)
callq 0x2f00
movq -0x118(%rbp), %rdi
leaq 0x3818(%rip), %rsi      # 0x609f
callq 0x2f20
jmp 0x288e
leaq -0x98(%rbp), %rdi
callq 0x2fa0
movq 0x7737(%rip), %rdi      # 0x9fd8
leaq 0x3818(%rip), %rsi      # 0x60c0
callq 0x20b0
movq %rax, %rdi
movq 0x7709(%rip), %rsi      # 0x9fc0
callq 0x20e0
leaq -0xa8(%rbp), %rdi
leaq 0x37d5(%rip), %rsi      # 0x609f
callq 0x3000
leaq -0xa8(%rbp), %rdi
callq 0x2d70
xorl %eax, %eax
addq $0x130, %rsp            # imm = 0x130
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x18(%rbp), %rdi
callq 0x2a70
jmp 0x29d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x2a70
jmp 0x29d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x2a70
jmp 0x29d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
jmp 0x2957
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x2d10
leaq -0x48(%rbp), %rdi
callq 0x2d70
jmp 0x29d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
jmp 0x2985
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x2a70
leaq -0x58(%rbp), %rdi
callq 0x2a70
jmp 0x29d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
jmp 0x29b3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x2a70
leaq -0x80(%rbp), %rdi
callq 0x2a70
jmp 0x29d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x98(%rbp), %rdi
callq 0x2fa0
movq -0x20(%rbp), %rdi
callq 0x2140
nop