// File: iZhangHui[P]CppPrimer/CH19_SpecializedToolsAndTechniques/examples/calc.cc
// Function: main
int main()
{
	function<int(int, int)> f1 = add;      // function pointer
	function<int(int, int)> f2 = divide(); // callable class type
	function<int(int, int)> f3 = [](int i, int j) // lambda
	                             { return i * j; };
	cout << f1(4,2) << endl; // prints 6
	cout << f2(4,2) << endl; // prints 2
	cout << f3(4,2) << endl; // prints 8

	// table of callable objects corresponding to each binary operator
	// all the callables must take two ints and return an int
	// an element can be a function pointer, function object, or lambda
	map<string, function<int(int, int)>> binops = {
		{"+", add},                  // function pointer
		{"-", std::minus<int>()},    // library function object
		{"/",  divide()},            // user-defined function object
		{"*", [](int i, int j) { return i * j; }}, // unnamed lambda
		{"%", mod} };                // named lambda object

	cout << binops["+"](10, 5) << endl; // calls add(10, 5)
	cout << binops["-"](10, 5) << endl; // uses the call operator of the minus<int> object
	cout << binops["/"](10, 5) << endl; // uses the call operator of the divide object
	cout << binops["*"](10, 5) << endl; // calls the lambda function object
	cout << binops["%"](10, 5) << endl; // calls the lambda function object

	// memp can point to either shift operation in ShiftOps
	// memp points to the Lshift member
	function<int (ShiftOps*, int, int)> memp = &ShiftOps::Lshift;  

	ShiftOps shift(cout);      // declare an object to which to bind the member pointer
	binops.insert({"<<", bind(memp, &shift, _1, _2)}); 
	cout << binops["<<"](10, 5) << endl; // calls member function
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x510, %rsp            # imm = 0x510
movl $0x0, -0x4(%rbp)
leaq -0x39(%rip), %rsi       # 0x2320
leaq -0x28(%rbp), %rdi
movq %rdi, -0x3c8(%rbp)
callq 0x3a80
leaq -0x48(%rbp), %rdi
leaq -0x49(%rbp), %rsi
callq 0x3b10
leaq -0x70(%rbp), %rdi
leaq -0x71(%rbp), %rsi
callq 0x2df0
movq -0x3c8(%rbp), %rdi
movl $0x4, %esi
movl $0x2, %edx
callq 0x3ba0
movl %eax, -0x3c0(%rbp)
jmp 0x23a1
movl -0x3c0(%rbp), %esi
movq 0xac22(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x3d0(%rbp)
jmp 0x23bc
movq -0x3d0(%rbp), %rdi
movq 0xabee(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x23d1
leaq -0x48(%rbp), %rdi
movl $0x4, %esi
movl $0x2, %edx
callq 0x3ba0
movl %eax, -0x3d4(%rbp)
jmp 0x23ec
movl -0x3d4(%rbp), %esi
movq 0xabd7(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x3e0(%rbp)
jmp 0x2407
movq -0x3e0(%rbp), %rdi
movq 0xaba3(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x241c
leaq -0x70(%rbp), %rdi
movl $0x4, %esi
movl $0x2, %edx
callq 0x3ba0
movl %eax, -0x3e4(%rbp)
jmp 0x2437
movl -0x3e4(%rbp), %esi
movq 0xab8c(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x3f0(%rbp)
jmp 0x2452
movq -0x3f0(%rbp), %rdi
movq 0xab58(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x2467
leaq -0x208(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x5c28(%rip), %rsi      # 0x80a4
leaq -0x163(%rip), %rdx      # 0x2320
callq 0x3bf0
jmp 0x248a
leaq -0x1c8(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x5c07(%rip), %rsi      # 0x80a6
leaq -0x211(%rbp), %rdx
callq 0x3c80
jmp 0x24ad
leaq -0x188(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x5be6(%rip), %rsi      # 0x80a8
leaq -0x212(%rbp), %rdx
callq 0x3d10
jmp 0x24d0
leaq -0x148(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x5bc5(%rip), %rsi      # 0x80aa
leaq -0x213(%rbp), %rdx
callq 0x2e80
jmp 0x24f3
leaq -0x108(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x5ba4(%rip), %rsi      # 0x80ac
leaq 0xabfb(%rip), %rdx      # 0xd10a
callq 0x2f10
jmp 0x2516
leaq -0x208(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq $0x5, -0xc0(%rbp)
leaq -0x215(%rbp), %rdi
movq %rdi, -0x3f8(%rbp)
callq 0x3dd0
movq -0x3f8(%rbp), %r8
movq -0xc8(%rbp), %rsi
movq -0xc0(%rbp), %rdx
leaq -0xb8(%rbp), %rdi
leaq -0x214(%rbp), %rcx
callq 0x3df0
jmp 0x256c
leaq -0x215(%rbp), %rdi
callq 0x3ec0
leaq -0x208(%rbp), %rax
movq %rax, -0x408(%rbp)
addq $0x140, %rax            # imm = 0x140
movq %rax, -0x400(%rbp)
movq -0x400(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x410(%rbp)
callq 0x3da0
movq -0x408(%rbp), %rcx
movq -0x410(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x400(%rbp)
jne 0x2593
leaq -0x239(%rbp), %rdi
movq %rdi, -0x418(%rbp)
callq 0x21d0
movq -0x418(%rbp), %rdx
leaq 0x5abf(%rip), %rsi      # 0x80a4
leaq -0x238(%rbp), %rdi
callq 0x2170
jmp 0x25f3
leaq -0xb8(%rbp), %rdi
leaq -0x238(%rbp), %rsi
callq 0x3ee0
movq %rax, -0x420(%rbp)
jmp 0x260f
movq -0x420(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3ba0
movl %eax, -0x424(%rbp)
jmp 0x262d
movl -0x424(%rbp), %esi
movq 0xa996(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x430(%rbp)
jmp 0x2648
movq -0x430(%rbp), %rdi
movq 0xa962(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x265d
leaq -0x238(%rbp), %rdi
callq 0x20c0
leaq -0x239(%rbp), %rdi
callq 0x2150
leaq -0x261(%rbp), %rdi
movq %rdi, -0x438(%rbp)
callq 0x21d0
movq -0x438(%rbp), %rdx
leaq 0x5a10(%rip), %rsi      # 0x80a6
leaq -0x260(%rbp), %rdi
callq 0x2170
jmp 0x26a4
leaq -0xb8(%rbp), %rdi
leaq -0x260(%rbp), %rsi
callq 0x3ee0
movq %rax, -0x440(%rbp)
jmp 0x26c0
movq -0x440(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3ba0
movl %eax, -0x444(%rbp)
jmp 0x26de
movl -0x444(%rbp), %esi
movq 0xa8e5(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x450(%rbp)
jmp 0x26f9
movq -0x450(%rbp), %rdi
movq 0xa8b1(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x270e
leaq -0x260(%rbp), %rdi
callq 0x20c0
leaq -0x261(%rbp), %rdi
callq 0x2150
leaq -0x289(%rbp), %rdi
movq %rdi, -0x458(%rbp)
callq 0x21d0
movq -0x458(%rbp), %rdx
leaq 0x5961(%rip), %rsi      # 0x80a8
leaq -0x288(%rbp), %rdi
callq 0x2170
jmp 0x2755
leaq -0xb8(%rbp), %rdi
leaq -0x288(%rbp), %rsi
callq 0x3ee0
movq %rax, -0x460(%rbp)
jmp 0x2771
movq -0x460(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3ba0
movl %eax, -0x464(%rbp)
jmp 0x278f
movl -0x464(%rbp), %esi
movq 0xa834(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x470(%rbp)
jmp 0x27aa
movq -0x470(%rbp), %rdi
movq 0xa800(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x27bf
leaq -0x288(%rbp), %rdi
callq 0x20c0
leaq -0x289(%rbp), %rdi
callq 0x2150
leaq -0x2b1(%rbp), %rdi
movq %rdi, -0x478(%rbp)
callq 0x21d0
movq -0x478(%rbp), %rdx
leaq 0x58b2(%rip), %rsi      # 0x80aa
leaq -0x2b0(%rbp), %rdi
callq 0x2170
jmp 0x2806
leaq -0xb8(%rbp), %rdi
leaq -0x2b0(%rbp), %rsi
callq 0x3ee0
movq %rax, -0x480(%rbp)
jmp 0x2822
movq -0x480(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3ba0
movl %eax, -0x484(%rbp)
jmp 0x2840
movl -0x484(%rbp), %esi
movq 0xa783(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x490(%rbp)
jmp 0x285b
movq -0x490(%rbp), %rdi
movq 0xa74f(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x2870
leaq -0x2b0(%rbp), %rdi
callq 0x20c0
leaq -0x2b1(%rbp), %rdi
callq 0x2150
leaq -0x2d9(%rbp), %rdi
movq %rdi, -0x498(%rbp)
callq 0x21d0
movq -0x498(%rbp), %rdx
leaq 0x5803(%rip), %rsi      # 0x80ac
leaq -0x2d8(%rbp), %rdi
callq 0x2170
jmp 0x28b7
leaq -0xb8(%rbp), %rdi
leaq -0x2d8(%rbp), %rsi
callq 0x3ee0
movq %rax, -0x4a0(%rbp)
jmp 0x28d3
movq -0x4a0(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3ba0
movl %eax, -0x4a4(%rbp)
jmp 0x28f1
movl -0x4a4(%rbp), %esi
movq 0xa6d2(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x4b0(%rbp)
jmp 0x290c
movq -0x4b0(%rbp), %rdi
movq 0xa69e(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x2921
leaq -0x2d8(%rbp), %rdi
callq 0x20c0
leaq -0x2d9(%rbp), %rdi
callq 0x2150
leaq 0x1680(%rip), %rax      # 0x3fc0
movq %rax, -0x310(%rbp)
movq $0x0, -0x308(%rbp)
leaq -0x300(%rbp), %rdi
leaq -0x310(%rbp), %rsi
callq 0x4020
movq 0xa664(%rip), %rsi      # 0xcfd0
leaq -0x318(%rbp), %rdi
callq 0x40c0
jmp 0x297a
leaq -0x318(%rbp), %rax
movq %rax, -0x388(%rbp)
movq 0xa639(%rip), %rcx      # 0xcfc8
movq 0xa65a(%rip), %r8       # 0xcff0
leaq -0x380(%rbp), %rdi
leaq -0x300(%rbp), %rsi
leaq -0x388(%rbp), %rdx
callq 0x4120
jmp 0x29b2
leaq 0x56f5(%rip), %rsi      # 0x80ae
leaq -0x358(%rbp), %rdi
leaq -0x380(%rbp), %rdx
callq 0x4170
jmp 0x29ce
leaq -0xb8(%rbp), %rdi
leaq -0x358(%rbp), %rsi
callq 0x40e0
movb %dl, -0x4b9(%rbp)
movq %rax, -0x4b8(%rbp)
jmp 0x29f0
movb -0x4b9(%rbp), %al
movq -0x4b8(%rbp), %rcx
movq %rcx, -0x398(%rbp)
movb %al, -0x390(%rbp)
leaq -0x358(%rbp), %rdi
callq 0x3da0
leaq -0x380(%rbp), %rdi
callq 0x4210
leaq -0x3b9(%rbp), %rdi
movq %rdi, -0x4c8(%rbp)
callq 0x21d0
movq -0x4c8(%rbp), %rdx
leaq 0x566b(%rip), %rsi      # 0x80ae
leaq -0x3b8(%rbp), %rdi
callq 0x2170
jmp 0x2a51
leaq -0xb8(%rbp), %rdi
leaq -0x3b8(%rbp), %rsi
callq 0x3ee0
movq %rax, -0x4d0(%rbp)
jmp 0x2a6d
movq -0x4d0(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3ba0
movl %eax, -0x4d4(%rbp)
jmp 0x2a8b
movl -0x4d4(%rbp), %esi
movq 0xa538(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, -0x4e0(%rbp)
jmp 0x2aa6
movq -0x4e0(%rbp), %rdi
movq 0xa504(%rip), %rsi      # 0xcfb8
callq 0x2140
jmp 0x2abb
leaq -0x3b8(%rbp), %rdi
callq 0x20c0
leaq -0x3b9(%rbp), %rdi
callq 0x2150
leaq -0x300(%rbp), %rdi
callq 0x4230
leaq -0xb8(%rbp), %rdi
callq 0x4250
leaq -0x70(%rbp), %rdi
callq 0x4270
leaq -0x48(%rbp), %rdi
callq 0x4270
leaq -0x28(%rbp), %rdi
callq 0x4270
movl -0x4(%rbp), %eax
addq $0x510, %rsp            # imm = 0x510
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2dbd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
movq -0x210(%rbp), %rax
leaq -0x208(%rbp), %rcx
cmpq %rax, %rcx
movq %rax, -0x4e8(%rbp)
je 0x2b80
movq -0x4e8(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x4f0(%rbp)
callq 0x3da0
movq -0x4f0(%rbp), %rax
leaq -0x208(%rbp), %rcx
cmpq %rcx, %rax
movq %rax, -0x4e8(%rbp)
jne 0x2b4f
jmp 0x2dbd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x215(%rbp), %rdi
callq 0x3ec0
leaq -0x208(%rbp), %rax
movq %rax, -0x500(%rbp)
addq $0x140, %rax            # imm = 0x140
movq %rax, -0x4f8(%rbp)
movq -0x4f8(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x508(%rbp)
callq 0x3da0
movq -0x500(%rbp), %rcx
movq -0x508(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x4f8(%rbp)
jne 0x2bbb
jmp 0x2dbd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2c1d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x238(%rbp), %rdi
callq 0x20c0
leaq -0x239(%rbp), %rdi
callq 0x2150
jmp 0x2db1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2c5a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x260(%rbp), %rdi
callq 0x20c0
leaq -0x261(%rbp), %rdi
callq 0x2150
jmp 0x2db1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2c97
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x288(%rbp), %rdi
callq 0x20c0
leaq -0x289(%rbp), %rdi
callq 0x2150
jmp 0x2db1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2cd4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x2b0(%rbp), %rdi
callq 0x20c0
leaq -0x2b1(%rbp), %rdi
callq 0x2150
jmp 0x2db1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2d11
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x2d8(%rbp), %rdi
callq 0x20c0
leaq -0x2d9(%rbp), %rdi
callq 0x2150
jmp 0x2db1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2da5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2d5f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x358(%rbp), %rdi
callq 0x3da0
leaq -0x380(%rbp), %rdi
callq 0x4210
jmp 0x2da5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2d99
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x3b8(%rbp), %rdi
callq 0x20c0
leaq -0x3b9(%rbp), %rdi
callq 0x2150
leaq -0x300(%rbp), %rdi
callq 0x4230
leaq -0xb8(%rbp), %rdi
callq 0x4250
leaq -0x70(%rbp), %rdi
callq 0x4270
leaq -0x48(%rbp), %rdi
callq 0x4270
leaq -0x28(%rbp), %rdi
callq 0x4270
movq -0x80(%rbp), %rdi
callq 0x21c0
nopw %cs:(%rax,%rax)