C++

[C++] 클래스 멤버 메소드를 함수포인터, std::function 객체로 변환하기

index1207 2023. 11. 6. 19:43

개발을 하다가 std::function이나 c타입의 함수 포인터에 클래스의 멤버 함수(=메소드)를

할당해야 할 때가 있다. 하지만 typeid로 멤버 함수의 타입을 보면 타입이 조금 다르다.

#include <iostream>

using namespace std;

class A {
public:
	A() {
		cout << typeid(&A::printHello).name() << '\n';
	}
public:
	void printHello() {
		cout << "Hello\n";
	}
};

int main() {
	A test;
}

/*
    결과 : void (A::*)(void) __ptr64
    원하는 결과 : void (void)
											 */

멤버 함수 타입을 보면 이상한 게 추가로 붙어 있다. 이를 통해 클래스의 멤버 함수는 일반적인 함수와 형식이 다르다는 것을 알 수 있는데, static 함수는 또 일반적인 함수로 인식한다. 하지만 우리가 메소드를 사용해야 하는 이유는 멤버변수에 접근을 할 수 있는 함수이기 때문이다.

 

이건 은근 간단하게 해결이 가능하다. 바로 std::bind를 사용하면 된다.

std::bind함수는 '함수 -> 객체'로 바꿔주는 함수로, 변환하기 전에 원하는 매개변수 자리나 값을 미리 정해 놓을 수 있다.

이 std::bind가 함수를 객체로 바꿔주는 기능 말고도, 멤버 함수를 일반 함수 객체로 바꿔주는 것도 가능하다.

// Bind의 일반적인 사용

int Add(int a, int b) {
	return a + b;
}

int main() {
	function<int()> add1 = bind(Add, 10, 20);
	cout << add1() << '\n';
	
	function<int(int)> add2 = bind(Add, 10, std::placeholders::_1);
	cout << add2(30) << '\n';

	function<int(int, int)> add3 = bind(Add, placeholders::_1, placeholders::_2);
	cout << add3(20, 30) << '\n';
}


// 클래스에서 멤버 함수를 일반함수로 변환

void print(function<string()> fs) {
	cout << fs() << '\n';
}

class A {
public:
	A() {
		print(&A::GetHello); // error
		print(bind(&A::GetHello, this));
	}
public:
	string GetHello() { return "Hello!"; }
};

int main() {
	A test;
}

std::bind(함수, 객체_포인터, std::placeholders::_1, ...) 이런식으로 사용할 수도 있다.

 

std::bind이외에도 람다표현식을 사용하는 것도 가능하다.

print([this]() {
	return GetHello();
});