C++获取函数的参数和返回值类型

First Post:

Blog Link:

C++函数主要分为两类:

  • 一类是继承自C的函数指针(普通函数可以通过std::decay后得到函数指针),其类型的模式可以直接写出:

  • template<typename R, typename ...As> R(*)(As...)

  • 另一类是可调用对象/函数对象,std::bindstd::function、lambda表达式等返回的都是函数对象。函数对象的类型没有一个固定的模式,但是都重载了operator(),而且其operator()函数的函数指针类型是可以模式化的:

  • template<typename R, typename C, typename ...As> R(C::*)(As...)

  • template<typename R, typename C, typename ...As> R(C::*)(As...) const

这样就可以用一些TMP技巧来对函数进行分类并用相应的模式萃取出其参数和返回值类型了:

  • 针对std::reference_wrapper<F>,递归对其中包裹的类型F进行萃取。
  • R(*)(...As)模式匹配函数指针进行萃取。
  • R(C::*)(...As)或者R(C::*)(...As) const模式匹配类函数指针进行萃取。
  • 否则,默认其为函数对象,递归对其重载的operator()函数指针进行萃取。

最后统一一个入口function_traits,先将传入的类型decay后(将函数转化为函数指针,去除引用,去除底层const等),再派发给__function_traits进行具体的匹配。

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
31
32
namespace detail {

template<typename R, typename ...As>
struct __function_traits_base {
using function_type = std::function<R(As...)>;

using result_type = R;

using argument_types = std::tuple<As...>;
};

template<typename F>
struct __function_traits;
template<typename F>
struct __function_traits<std::reference_wrapper<F>> : public __function_traits<F> {};
template<typename R, typename ...As>
struct __function_traits<R(*)(As...)> : public __function_traits_base<R, As...> {};
template<typename R, typename C, typename ...As>
struct __function_traits<R(C::*)(As...)> : public __function_traits_base<R, As...> {};
template<typename R, typename C, typename ...As>
struct __function_traits<R(C::*)(As...) const> : public __function_traits_base<R, As...> {};
template<typename F>
struct __function_traits : public __function_traits<decltype(&F::operator())> {};

}

namespace fp {

template<typename F>
struct function_traits : public detail::__function_traits<std::decay_t<F>> {};

}