// 함수 포인터 정의 방법
void func(float a) {
	cout << "func 의 매개변수는 " << a << "입니다." << endl;
}

int func2(int a, float b) {
	cout << "func2 의 매개변수는 " << a << "와 " << b << "입니다." << endl;
	return 0;
}

int main() {
	void(*funcPtr)(float) = func;
	func(3);
	funcPtr(3);

	int(*funcPtr2)(int, float) = func2;
	func2(10, 2.0f);
	funcPtr2(10, 2.0f);
}

// 함수의 return (*포인터이름)(매개변수 타입) = func
bool isEven(const int& number) {
	if (number % 2 == 0) return true;
	return false;
}

bool isOdd(const int& number) {
	if (number % 2 == 1) return true;
	return false;
}

void printNumber(std::array<int, 10>& arr, bool(*check_func)(const int&)) {

	for (const auto& element : arr) {
		if(check_func(element) == true)
			cout << element << " ";
	}
	cout << endl;
}

int main() {
	std::array<int, 10> arr{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	printNumber(arr, isEven); // 2 4 6 8 10
	printNumber(arr, isOdd); // 1 3 5 7 9
}
// using 과 typedef 를 사용해서 함수포인터 표현
using check_func = bool(*)(const int&);
// bool(*)(const int&) 데이터 타입을 check_func 로 쓸 수 있다.

typedef bool(*check_func)(const int&);
check_func func_ptr = isEven;
// bool(*)(const int&) 데이터 타입을 check_func 로 쓸 수 있다.
#include <functional>

void printFunc(const int& a) {
	cout << "func 의 매개변수는 " << a << " 입니다." << endl;
}

struct S {
	void operator()() {
		cout << "구조체 S의 함수입니다." << endl;
	}
};

int main() {
	std::function<void(const int &)> func1 = printFunc;
	std::function<void()> func2 = S();
	std::function<void()> func3 = []() {cout << "func3 함수 입니다." << endl; };

	func1(10);
	func2();
	func3();
}
// 멤버 함수를 함수 포인터로
// & 클래스 이름 :: 함수 이름
// 멤버 변수는 각 객체들마다 따로 메모리를 가져서 주소가 다르다. 하지만!
// 멤버 함수는 메모리를 따로 갖지 않는다. 한군데에 저장해 놓고 각 객체마다 그 공간에
// 동일하게 접근해서 각자의 다른 데이터로 사용한다.
// 멤버 함수의 주소를 받아와야 하고, 그러기 위해서 속해있는 클래스를 알려주어야 한다.
class Test
{
public:
	int temp(const int& num) { return num * 10; }
};

int main() {
	Test t;
	int(Test::*func)(const int&) = &Test::temp;
	cout << (t.*func)(10)<< endl; // (객체.*함수포인터)(매개변수)  100
}
// static 멤버 함수
// 객체와 무관하게 연산이 이루어지기 때문에 일반함수 포인터로 취급받는다.
class Test
{
public:
	int temp(const int& num) { return num * 10; }
	static int staticTemp(const int& num) { return num * 10; }
};

int main() {
	int(*sFunc)(const int& num) = Test::staticTemp;
	cout << sFunc(10) << endl; // 100	
}