2 min read

C++ std::function 구현에 대해

오래전부터 std::function에 대해 꽤 궁금해왔다.

그 이유는 std::function<int(void)> 이런 형태이기 때문이다.

이를 어떻게 만들려면 어떻게 해야하나

맨첨에 생각할때는 다음과 같이 생각하였지만.

이는 내가 원하는 방식이 아니므로 넘어갔다.

1
2
3
4
5
6
template <typename T, typename… Args>
class function{
}
cs

비주얼 스튜디오에는 std::function코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
template<class _Tx>
    struct _Get_function_impl;
#define _GET_FUNCTION_IMPL(CALL_OPT, X1, X2, X3) \
template<class _Ret, \
    class… _Types> \
    struct _Get_function_impl<_Ret CALL_OPT (_Types…)> \
    {    /* determine type from argument list */ \
    typedef _Func_class<_Ret, _Types…> type; \
    };
};
// CLASS TEMPLATE function
template<class _Fty>
    class function
        : public _Get_function_impl<_Fty>::type
    {    // wrapper for callable objects
private:
    typedef typename _Get_function_impl<_Fty>::type _Mybase;
public:
    function() _NOEXCEPT
        {    // construct empty function wrapper
        }
    function(nullptr_t) _NOEXCEPT
        {    // construct empty function wrapper from null pointer
        }
cs

위 소스를 보면 std::function<int(void)> 이게 왜 되는지 이해가 됬다.

템플릿 인자안에 들어가는 int(void)이부분이 이미 타입이 여러개가 아니라 타입이기 때문에 템플릿 인자에 하나만 넣은거다.

_Get_function_impl클래스는 다음과같다.

1
template<class _Tx>
    struct _Get_function_impl;
#define _GET_FUNCTION_IMPL(CALL_OPT, X1, X2, X3) \
template<class _Ret, \
    class… _Types> \
    struct _Get_function_impl<_Ret CALL_OPT (_Types…)> \
    {    /* determine type from argument list */ \
    typedef _Func_class<_Ret, _Types…> type; \
    };
};
typedef typename _Get_function_impl<_Fty>::type _Mybase;
cs

_Get_function_impl은 먼저 몸체없이 전방선언을 해두고 아래에 특수화 한번 해주었다.

그로 인해 반환형도 쉽게 구분 지울수 있게된다.

이해 하기 힘들거같아 다음과 같이 프로토타입을 만들어 두었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template <typename T>
class function;
template <typename R, typename… Args>
class function<R(Args…)>
{
public:
    typedef R(*np)(Args…);
    np a;
};
void fn(int a) {
    std::cout << “asdad”;
}
int main() {
    function<void(int)> a;
    a.a = fn;
    a.a(10);
}
cs