1. 程式人生 > >C++程式碼片段(一)萃取函式返回值型別,引數型別,引數個數

C++程式碼片段(一)萃取函式返回值型別,引數型別,引數個數

函式的型別主要集中在以下幾種

  • 函式指標
  • 函式物件,是一個類物件,內部過載的operator()函式是一個函式指標
  • lambda,匿名函式物件,同函式物件
  • function物件

後三者都是類物件,可以看成一種型別

定義基礎模板類

template <typename T>
struct function_traits;

針對函式指標進行偏特化

對於函式指標,存在兩種情況

  • 直接通過decltype獲取型別
  • 利用模板推導型別
int pointer_func(int a, int b) {
    return a + b;
}
// decltype(pointer_func) is int
(int, int)
int pointer_func(int a, int b) {
    return a + b;
}
template <typename Func>
void traits_test1(Func&&) {

}
template <typename Func>
void traits_test2(Func) {

}
int main() {
    // Func = int(&)(int, int)
    traits_test1(pointer_func);

    // Func = int(*)(int, int)
traits_test2(pointer_func); }

不難發現,函式指標的型別為

  • R(*)(Args…)
  • R(&)(Args…)
  • R(Args…)

其中R是函式返回值型別,Args是函式的引數列表,針對這三種進行特化

template <typename R, typename... Args>
struct function_traits_helper
{
    static constexpr auto param_count = sizeof...(Args);
    using return_type = R;

    template
<std::size_t N> using param_type = std::tuple_element_t<N, std::tuple<Args...>>; }; // int(*)(int, int) template <typename R, typename... Args> struct function_traits<R(*)(Args...)> : public function_traits_helper<R, Args...> { }; // int(&)(int, int) template <typename R, typename... Args> struct function_traits<R(&)(Args...)> : public function_traits_helper<R, Args...> { }; // int(int, int) template <typename R, typename... Args> struct function_traits<R(Args...)> : public function_traits_helper<R, Args...> { };

針對lambda進行偏特化

假設在main函式中定義一個匿名函式lambda,通過模板引數型別推導判斷它的型別

template <typename Func>
void traits_test(Func&&) {

}

int main()
{
    auto f = [](int a, int b) { return a + b; };
    // Func = main()::<lambda(int, int)> const
    // Func::operator() = int(main()::<lambda(int, int)>*)(int, int) const
    traits_test(f);
    return 0;
}

lambda實際上是一個匿名函式物件,可以理解為內部也過載了operator()函式,所以如果將lambda整體進行推導,那麼會推匯出一個main()::

template <typename R, typename... Args>
struct function_traits_helper
{
    static constexpr auto param_count = sizeof...(Args);
    using return_type = R;

    template <std::size_t N>
    using param_type = std::tuple_element_t<N, std::tuple<Args...>>;
};

template <typename ClassType, typename R, typename... Args>
struct function_traits<R(ClassType::*)(Args...) const> : public function_traits_helper<R, Args...>
{
    using class_type = ClassType;
};

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {};

通過std::function和std::bind繫結的函式物件和lambda型別相同,不需要額外的特化

增加const版本

針對某些可能推匯出const的增加const版本,比如上述的lambda

完整程式碼請參考這裡