C++

C++ std::function 와 std::bind 사용법

std::function 란?

C++11 부터 추가된 기능으로, C의 함수 포인터를 대체한다.
아래와 같이 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
void addAndPrint(int a, int b)
{
int sum = a + b;
std::cout << sum << "\n";
}

std::function<void(int, int)> func1 = addAndPrint;

// 아래 두 줄은 똑같이 작동한다
addAndPrint(10, 20);
func1(10, 20);

위에선 전역으로 선언된 addAndPrint 함수를 std::function 으로 받고 있다.
만약 class 의 멤버함수를 가르키고 싶으면, 위와는 조금 다르게 사용해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
public:
void addAndPrint(int a, int b)
{
int sum = a + b;
std::cout << "sum: " << sum << "\n";
}
};

A test;
// 매개변수로 객체를 전달해야한다
std::function<void(A&, int, int)> func3 = &A::addAndPrint;
func3(test, 10, 20);

위처럼 멤버함수를 위해서 어떤 객체의 멤버함수를 실행할 지 알 수 있도록 객체를 전달해야 한다.
그리고 13번째 줄에서 A의 addAndPrint 를 대입하기 위해 &A::addAndPrint 처럼 앞에 & 를 사용하고 있는데, 이 이유는 멤버함수의 경우엔 함수의 주소값으로 암시적 형변환이 되지 않아서, 명시적으로 &를 사용해서 주소값을 전달해줘야 하기 때문이다.

std::bind 란?

std::function 과 마찬가지로 C++11 기능이며, 함수의 인자를 지정할 수 있다.

1
2
3
4
5
6
7
8
void addAndPrint(int a, int b)
{
int sum = a + b;
std::cout << sum << "\n";
}

auto func2 = std::bind(addAndPrint, 10, std::placeholders::_1);
func2(100); // addAndPrint(10, 100); 과 동일한 결과를 보장함

위 코드부턴 auto 를 사용했는데, 여기선 std::function<void(int)> 와 동일하다.
std::bind(addAndPrint, 10, std::placeholders::_1) 의 의미는 addAndPrint(int, int) 함수의 첫 번째 파라메터는 10, 두 번째 파라메터는 func2 를 호출할 때 들어오는 첫번째 인자를 넣어준다는 의미다.

클래스 멤버함수를 클래스 내부에서 bind 시켜주는 예제를 한번 작성해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A
{
public:
void addAndPrint(int a, int b)
{
int sum = a + b;
std::cout << "sum: " << sum << "\n";
}

void bindFunction(std::function<void(int, int)>& dest)
{
dest = std::bind(&A::addAndPrint, this, std::placeholders::_1, std::placeholders::_2);
}
};

A test;
std::function<void(int, int)> func4;
test.bindFunction(func4);
func4(100, 200);

func4는 객체 바깥에서 선언되고, A::bindFunction 에 의해서 test.addAndPrint 와 동일한 동작을 하는 함수로 bind 되었다.