// File: iZhangHui[P]CppPrimer/CH14_OverloadedOperationsAndConversions/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
	cout << "==================" << endl;
	// 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

	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x400, %rsp            # imm = 0x400
movl $0x0, -0x4(%rbp)
leaq -0x39(%rip), %rsi       # 0x2310
leaq -0x28(%rbp), %rdi
movq %rdi, -0x2e8(%rbp)
callq 0x3860
leaq -0x48(%rbp), %rdi
leaq -0x49(%rbp), %rsi
callq 0x38f0
leaq -0x70(%rbp), %rdi
leaq -0x71(%rbp), %rsi
callq 0x2bd0
movq -0x2e8(%rbp), %rdi
movl $0x4, %esi
movl $0x2, %edx
callq 0x3980
movl %eax, -0x2e0(%rbp)
jmp 0x2391
movl -0x2e0(%rbp), %esi
movq 0x8c3a(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x2f0(%rbp)
jmp 0x23ac
movq -0x2f0(%rbp), %rdi
movq 0x8c0e(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x23c1
leaq -0x48(%rbp), %rdi
movl $0x4, %esi
movl $0x2, %edx
callq 0x3980
movl %eax, -0x2f4(%rbp)
jmp 0x23dc
movl -0x2f4(%rbp), %esi
movq 0x8bef(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x300(%rbp)
jmp 0x23f7
movq -0x300(%rbp), %rdi
movq 0x8bc3(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x240c
leaq -0x70(%rbp), %rdi
movl $0x4, %esi
movl $0x2, %edx
callq 0x3980
movl %eax, -0x304(%rbp)
jmp 0x2427
movl -0x304(%rbp), %esi
movq 0x8ba4(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x310(%rbp)
jmp 0x2442
movq -0x310(%rbp), %rdi
movq 0x8b78(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x2457
movq 0x8b7a(%rip), %rdi      # 0xafd8
leaq 0x4c1f(%rip), %rsi      # 0x7084
callq 0x2100
movq %rax, -0x318(%rbp)
jmp 0x2473
movq -0x318(%rbp), %rdi
movq 0x8b47(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x2488
leaq -0x208(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x4bfa(%rip), %rsi      # 0x7097
leaq -0x194(%rip), %rdx      # 0x2310
callq 0x39d0
jmp 0x24ab
leaq -0x1c8(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x4bd9(%rip), %rsi      # 0x7099
leaq -0x211(%rbp), %rdx
callq 0x3a60
jmp 0x24ce
leaq -0x188(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x4bb8(%rip), %rsi      # 0x709b
leaq -0x212(%rbp), %rdx
callq 0x3af0
jmp 0x24f1
leaq -0x148(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x4b97(%rip), %rsi      # 0x709d
leaq -0x213(%rbp), %rdx
callq 0x2c60
jmp 0x2514
leaq -0x108(%rbp), %rdi
movq %rdi, -0x210(%rbp)
leaq 0x4b76(%rip), %rsi      # 0x709f
leaq 0x8bd2(%rip), %rdx      # 0xb102
callq 0x2cf0
jmp 0x2537
leaq -0x208(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq $0x5, -0xc0(%rbp)
leaq -0x215(%rbp), %rdi
movq %rdi, -0x320(%rbp)
callq 0x3bb0
movq -0x320(%rbp), %r8
movq -0xc8(%rbp), %rsi
movq -0xc0(%rbp), %rdx
leaq -0xb8(%rbp), %rdi
leaq -0x214(%rbp), %rcx
callq 0x3bd0
jmp 0x258d
leaq -0x215(%rbp), %rdi
callq 0x3ca0
leaq -0x208(%rbp), %rax
movq %rax, -0x330(%rbp)
addq $0x140, %rax            # imm = 0x140
movq %rax, -0x328(%rbp)
movq -0x328(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x338(%rbp)
callq 0x3b80
movq -0x330(%rbp), %rcx
movq -0x338(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x328(%rbp)
jne 0x25b4
leaq -0x239(%rbp), %rdi
movq %rdi, -0x340(%rbp)
callq 0x21c0
movq -0x340(%rbp), %rdx
leaq 0x4a91(%rip), %rsi      # 0x7097
leaq -0x238(%rbp), %rdi
callq 0x2160
jmp 0x2614
leaq -0xb8(%rbp), %rdi
leaq -0x238(%rbp), %rsi
callq 0x3cc0
movq %rax, -0x348(%rbp)
jmp 0x2630
movq -0x348(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3980
movl %eax, -0x34c(%rbp)
jmp 0x264e
movl -0x34c(%rbp), %esi
movq 0x897d(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x358(%rbp)
jmp 0x2669
movq -0x358(%rbp), %rdi
movq 0x8951(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x267e
leaq -0x238(%rbp), %rdi
callq 0x20c0
leaq -0x239(%rbp), %rdi
callq 0x2150
leaq -0x261(%rbp), %rdi
movq %rdi, -0x360(%rbp)
callq 0x21c0
movq -0x360(%rbp), %rdx
leaq 0x49e2(%rip), %rsi      # 0x7099
leaq -0x260(%rbp), %rdi
callq 0x2160
jmp 0x26c5
leaq -0xb8(%rbp), %rdi
leaq -0x260(%rbp), %rsi
callq 0x3cc0
movq %rax, -0x368(%rbp)
jmp 0x26e1
movq -0x368(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3980
movl %eax, -0x36c(%rbp)
jmp 0x26ff
movl -0x36c(%rbp), %esi
movq 0x88cc(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x378(%rbp)
jmp 0x271a
movq -0x378(%rbp), %rdi
movq 0x88a0(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x272f
leaq -0x260(%rbp), %rdi
callq 0x20c0
leaq -0x261(%rbp), %rdi
callq 0x2150
leaq -0x289(%rbp), %rdi
movq %rdi, -0x380(%rbp)
callq 0x21c0
movq -0x380(%rbp), %rdx
leaq 0x4933(%rip), %rsi      # 0x709b
leaq -0x288(%rbp), %rdi
callq 0x2160
jmp 0x2776
leaq -0xb8(%rbp), %rdi
leaq -0x288(%rbp), %rsi
callq 0x3cc0
movq %rax, -0x388(%rbp)
jmp 0x2792
movq -0x388(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3980
movl %eax, -0x38c(%rbp)
jmp 0x27b0
movl -0x38c(%rbp), %esi
movq 0x881b(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x398(%rbp)
jmp 0x27cb
movq -0x398(%rbp), %rdi
movq 0x87ef(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x27e0
leaq -0x288(%rbp), %rdi
callq 0x20c0
leaq -0x289(%rbp), %rdi
callq 0x2150
leaq -0x2b1(%rbp), %rdi
movq %rdi, -0x3a0(%rbp)
callq 0x21c0
movq -0x3a0(%rbp), %rdx
leaq 0x4884(%rip), %rsi      # 0x709d
leaq -0x2b0(%rbp), %rdi
callq 0x2160
jmp 0x2827
leaq -0xb8(%rbp), %rdi
leaq -0x2b0(%rbp), %rsi
callq 0x3cc0
movq %rax, -0x3a8(%rbp)
jmp 0x2843
movq -0x3a8(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3980
movl %eax, -0x3ac(%rbp)
jmp 0x2861
movl -0x3ac(%rbp), %esi
movq 0x876a(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x3b8(%rbp)
jmp 0x287c
movq -0x3b8(%rbp), %rdi
movq 0x873e(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x2891
leaq -0x2b0(%rbp), %rdi
callq 0x20c0
leaq -0x2b1(%rbp), %rdi
callq 0x2150
leaq -0x2d9(%rbp), %rdi
movq %rdi, -0x3c0(%rbp)
callq 0x21c0
movq -0x3c0(%rbp), %rdx
leaq 0x47d5(%rip), %rsi      # 0x709f
leaq -0x2d8(%rbp), %rdi
callq 0x2160
jmp 0x28d8
leaq -0xb8(%rbp), %rdi
leaq -0x2d8(%rbp), %rsi
callq 0x3cc0
movq %rax, -0x3c8(%rbp)
jmp 0x28f4
movq -0x3c8(%rbp), %rdi
movl $0xa, %esi
movl $0x5, %edx
callq 0x3980
movl %eax, -0x3cc(%rbp)
jmp 0x2912
movl -0x3cc(%rbp), %esi
movq 0x86b9(%rip), %rdi      # 0xafd8
callq 0x21a0
movq %rax, -0x3d8(%rbp)
jmp 0x292d
movq -0x3d8(%rbp), %rdi
movq 0x868d(%rip), %rsi      # 0xafc8
callq 0x2140
jmp 0x2942
leaq -0x2d8(%rbp), %rdi
callq 0x20c0
leaq -0x2d9(%rbp), %rdi
callq 0x2150
movl $0x0, -0x4(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x3da0
leaq -0x70(%rbp), %rdi
callq 0x3dc0
leaq -0x48(%rbp), %rdi
callq 0x3dc0
leaq -0x28(%rbp), %rdi
callq 0x3dc0
movl -0x4(%rbp), %eax
addq $0x400, %rsp            # imm = 0x400
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2ba5
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, -0x3e0(%rbp)
je 0x2a02
movq -0x3e0(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x3e8(%rbp)
callq 0x3b80
movq -0x3e8(%rbp), %rax
leaq -0x208(%rbp), %rcx
cmpq %rcx, %rax
movq %rax, -0x3e0(%rbp)
jne 0x29d1
jmp 0x2ba5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x215(%rbp), %rdi
callq 0x3ca0
leaq -0x208(%rbp), %rax
movq %rax, -0x3f8(%rbp)
addq $0x140, %rax            # imm = 0x140
movq %rax, -0x3f0(%rbp)
movq -0x3f0(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x400(%rbp)
callq 0x3b80
movq -0x3f8(%rbp), %rcx
movq -0x400(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x3f0(%rbp)
jne 0x2a3d
jmp 0x2ba5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2a9f
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 0x2b99
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2adc
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 0x2b99
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2b19
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 0x2b99
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2b53
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 0x2b99
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x2b8d
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
leaq -0xb8(%rbp), %rdi
callq 0x3da0
leaq -0x70(%rbp), %rdi
callq 0x3dc0
leaq -0x48(%rbp), %rdi
callq 0x3dc0
leaq -0x28(%rbp), %rdi
callq 0x3dc0
movq -0x80(%rbp), %rdi
callq 0x21b0
nopl (%rax)