std::function은 C++11 표준 라이브러리의 한 템플릿으로, 함수 포인터 개념을 일반화한 것 이다.
C++에서는 'Callable'들을 객체의 형태로 보관할 수 있는 std::funciton 이라는 클래스를 제공한다. C에서의 함수 포인터는 진짜 함수들만 보관할 수 있는 객체라고 보았다면, 이 std::function은 함수 뿐만 아니라 모든 Callable들을 보관할 수 있다.
그럼 Callable은 무엇인가?
C++에서 호출 가능한 모든 것을 포괄해서 나타내는 것이다. C++에서 ()를 붙여서 호출할 수 있는 모든 것을 Callable이라고 한다.
typedef struct _s_oper
{
void operator() ( int nA, int nB ) {
std::cout << "nA * nB = " << nA*nB << std::endl;
}
}S_oper;
auto _tmain(int argc, _TCHAR* argv[]) -> int
{
S_oper s;
s(3,5); // 실제로는 s.operator() (3,5);
/* 위에서 s는 마치 함수처럼 호출되지만 함수가 아니다.
엄밀히 말하면 S_oper의 인스턴스, 즉 객체이다.
*/
}
C++의 Callable의 개념을 알았다면 다시 std::function으로 돌아오자. std::function 은 이러한 Callable 속성을 가진 모든 것들을 객체 형태로 보관할 수 있는 객체이다.
위의 예시에서처럼 구조체 내에 정의한 함수의 주소도 받을 수 있고, 일반적으로 선언한 함수의 주소도 받을 수 있다.
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <functional>
void func_oper(int nA, int nB)
{
std::cout << "func_oper : nA * nB = " << nA*nB << std::endl;
}
typedef struct _s_oper
{
void operator() ( int nA, int nB ) { std::cout << "s_oper : nA * nB = " << nA*nB << std::endl; }
}S_oper;
auto _tmain(int argc, _TCHAR* argv[]) -> int
{
S_oper s
std::function< void(int, int) > func1 = func_oper; // func1에 func_oper의 주소를 저장
std::function< void(int, int) > func2 = S_oper(); // func2에 S_oper의 () operator의 주소를 저장
func1(10,20);
func2(30,40);
}
하지만 function은 일반적인 Callable 들을 보관할 수 있지만, 멤버함수의 경우는 얘기가 달라진다.
왜냐햐면 멤버 함수 내에서는 클래스의 내부 데이터에 접근하는데 (*만약 내부 데이터에 접근하지 않는다! 라고 하면 클래스로 정의하지말고 함수 포인터만 갖는 구조체로 정의하는게 나을 것이다.) 멤버 함수에 접근할 때 (명시적으로든 암묵적으로든 호출되는) this의 경우 자신을 호출한 객체를 의미하기 때문에, std::function에 멤버 함수를 넣으면 this가 무엇인지 알 방법이 없다.
따라서 std::function 으로 선언한 함수 객체에 멤버 함수 주소를 넣으면 컴파일 에러가 난다.
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <functional>
void func_print(int _a)
{
std::cout << "func_print = " << _a << std::endl;
}
class CA
{
public:
CA(int _Num) : m_Num(_Num) {};
~CA (){};
void do_print()
{
std::cout << "this m_Num = " << m_Num << std::endl;
}
private:
int m_Num;
};
auto _tmain(int argc, _TCHAR* argv[]) -> int
{
CA instA(5);
std::function<void(int)> func1 = func_print;
std::function<void(void) > func2 = &CA::do_print; // compile error
}
그럼 어떻게 해야하나?
원래 인자에 추가적으로 객체를 받는 인자를 전달해주면 된다.
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <functional>
void func_print(int _a)
{
std::cout << "func_print = " << _a << std::endl;
}
class CA
{
public:
CA(int _Num) : m_Num(_Num) {};
~CA (){};
void do_print(int _n)
{
std::cout << "this parameter = " << _n << std::endl;
std::cout << "this m_Num = " << m_Num << std::endl;
}
private:
int m_Num;
};
auto _tmain(int argc, _TCHAR* argv[]) -> int
{
std::function<void(int)> func1 = func_print;
CA instA(5);
std::function< void(CA& , int) > func2 = &CA::do_print; // 컴파일 오류... 응?
func2(instA, 10);
}
뭐야 컴파일 된다매 ㅠㅠ 왜 안되냐 ㅠㅠ 근데 오류가 템플릿에 인자 잘못전달했다는 오류라서 알아볼 수가 없다
다시 템플릿 공부부터 해야 디버깅이 될 것 같다..
오류 내용
error C2664: 'std::_Func_class<_Ret,_V0_t,_V1_t>::_Set' : 매개 변수 1을(를) '_Myimpl *'에서 'std::_Func_base<_Rx,_V0_t,_V1_t> *'(으)로 변환할 수 없습니다.
1> with
1> [
1> _Ret=void,
1> _V0_t=CA &,
1> _V1_t=int
1> ]
1> and
1> [
1> _Rx=void,
1> _V0_t=CA &,
1> _V1_t=int
1> ]
1> 가리킨 형식이 관련이 없습니다. 변환하려면 reinterpret_cast, C 스타일 캐스트 또는 함수 스타일 캐스트가 필요합니다.
'Dev Language > Modern C++ (C++11, 14)' 카테고리의 다른 글
C++ 11 : 열거타입 enum (0) | 2020.08.08 |
---|---|
C++ 11 : nullptr (0) | 2020.08.08 |
C++ 11 : auto_ptr (0) | 2020.08.08 |
C++ 11 : unique_ptr (0) | 2020.08.08 |
C++ 11 : shared_ptr (0) | 2020.08.08 |