// File: /workspace/github_cpp_makefile_star2_O2/iZhangHui[P]CppPrimer/CH19_SpecializedToolsAndTechniques/examples/useScreen.cc
// Function: main
int main ()
{
	// pdata can point to a string member of a const (or nonconst) Screen
	const string Screen::*pdata;  // uninitialized
	pdata = &Screen::contents;    // points to the contents member
	auto pdata2 = &Screen::contents; // equivalent declaration

	// data() returns a pointer to the contents member of class Screen
	const string Screen::*pdata3 = Screen::data();
	
	// Screen objects
	Screen myScreen, *pScreen = &myScreen;
	const Screen cScreen, *pcScreen = &cScreen;

	// .* dereferences pdata to fetch the contents member 
	// from the object myScreen
	auto str = myScreen.*pdata;  // s is a string
	auto cstr = cScreen.*pdata;  // c is a const string
	
	// ->* dereferences pdata to fetch contents 
	// from the object to which pScreen points
	str = pScreen->*pdata;  
	
	// pmf is a pointer that can point to a Screen member function 
	// that takes no arguments, returns a char, and is const
	// that returns a char and takes no arguments
	auto pmf = &Screen::get_cursor;
	char (Screen::*pmf2)() const = &Screen::get; // same type as pmf
	
	pmf = &Screen::get; // which version of get deduced from type of pmf
	pmf2 = &Screen::get_cursor;
	
	Screen s;
	char c1 = s.get_cursor(); // gets character at the cursor directly
	char c2 = (s.*pmf2)();    // calls get_cursor indirectly through pmf2
	
	// call the function to which pmf points 
	// on the object to which pScreen points
	c1 = (pScreen->*pmf)();  
	
	// pmf3 points to the two-parameter version of get
	char (Screen::*pmf3)(Screen::pos, Screen::pos) const = &Screen::get;
	c1 = myScreen.get(0,0);     // call two-parameter version of get 
	c2 = (myScreen.*pmf3)(0,0); // equivalent call to get
	
	// Op is a type that can point to a member function of Screen 
	// that returns a char and takes two pos arguments
	using Op = char (Screen::*)(Screen::pos, Screen::pos) const;
	// equivalent declaration of Op using a typedef
	typedef char (Screen::*Op)(Screen::pos, Screen::pos) const;

	Op get = &Screen::get; // get points to the get member of Screen
	
	myScreen.move(Screen::HOME);  // invokes myScreen.home
	myScreen.move(Screen::DOWN);  // invokes myScreen.down

	// bind an object of type function to a pointer to member
	function<char (const Screen*)> f = &Screen::get_cursor;

	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
subq $0x108, %rsp            # imm = 0x108
leaq -0x60(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x14f2
leaq -0xb8(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x14f2
leaq -0x28(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0x10c0
leaq -0x80(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x10c0
leaq -0x28(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0x1080
leaq -0xf0(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x14f2
leaq -0x60(%rbp), %rdi
xorl %esi, %esi
callq 0x1544
leaq -0x60(%rbp), %rdi
pushq $0x4
popq %rsi
callq 0x1544
leaq 0x1eb(%rip), %rax       # 0x1534
leaq -0x110(%rbp), %rdi
movq %rax, (%rdi)
andq $0x0, 0x8(%rdi)
leaq 0x2bf(%rip), %rax       # 0x161e
movq %rax, 0x18(%rdi)
leaq 0x2be(%rip), %rax       # 0x1628
movq %rax, 0x10(%rdi)
callq 0x156e
leaq -0xf0(%rbp), %rdi
callq 0x1060
leaq -0x80(%rbp), %rdi
callq 0x1060
leaq -0x28(%rbp), %rdi
callq 0x1060
leaq -0xb8(%rbp), %rdi
callq 0x1060
leaq -0x60(%rbp), %rdi
callq 0x1060
xorl %eax, %eax
addq $0x108, %rsp            # imm = 0x108
popq %rbx
popq %rbp
retq
jmp 0x13b4
movq %rax, %rbx
jmp 0x13d7
movq %rax, %rbx
jmp 0x13e0
movq %rax, %rbx
jmp 0x13e9
movq %rax, %rbx
jmp 0x13f5
movq %rax, %rbx
leaq -0xf0(%rbp), %rdi
callq 0x1060
leaq -0x80(%rbp), %rdi
callq 0x1060
leaq -0x28(%rbp), %rdi
callq 0x1060
leaq -0xb8(%rbp), %rdi
callq 0x1060
leaq -0x60(%rbp), %rdi
callq 0x1060
movq %rbx, %rdi
callq 0x10f0