function_traits2 通过对函数特征的学习深入理解模板

通过对函数特征的学习深入理解模板

/*
 * 函数特征
 *  学习及改进自《深入应用C++11 代码优化与工程级应用》
 *
 * 符号概念:
 *  F       - 函数概念(可调用对象)
 *  R       - 返回值类型
 *  K       - 类(class)类型
 *  Args... - 形参类型包
 */
#ifndef __FUNCTION_TRAITS_H__
#define __FUNCTION_TRAITS_H__

#include <functional>
#include <tuple>
#include <type_traits>

// 主模板
template <typename F>
struct function_traits;

// 普通函数特征
template<typename R, typename... Args>
struct function_traits<R(Args...)>
{
    enum { arity = sizeof...(Args) };
    using return_type       = R;
    using function_type     = R(Args...);
    using stl_function_type = std::function<function_type>;
    using pointer           = R(*)(Args...);

    template<size_t I>
    using type = typename std::tuple_element<I, std::tuple<Args...>>::type;

    template<size_t I>
    struct args
    {
        static_assert(I < arity, "Index must less than sizeof Args.");
        using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
    };
};

// 函数指针特征
template<typename R, typename... Args>
struct function_traits<R(*)(Args...)> : function_traits<R(Args...)> {};

// std::function 特征
template<typename R, typename... Args>
struct function_traits<std::function<R(Args...)>> : function_traits<R(Args...)> {};

// 成员函数特征
#define KLASS_MEMBER_FUNCTION_TRAITS(...)\
template<typename R, typename K, typename... Args>\
struct function_traits<R(K::*)(Args...) __VA_ARGS__ > : function_traits<R(Args...)> {};

KLASS_MEMBER_FUNCTION_TRAITS()
KLASS_MEMBER_FUNCTION_TRAITS(const)
KLASS_MEMBER_FUNCTION_TRAITS(volatile)
KLASS_MEMBER_FUNCTION_TRAITS(const volatile)
#undef KLASS_MEMBER_FUNCTION_TRAITS

// std::bind 特征匹配
template <typename R, typename F, typename... Args>
struct function_traits<std::_Binder<R, F, Args...>> : function_traits<F> {};

// 仿函数特征
template<typename F>
struct function_traits : function_traits<decltype(&F::operator())> {};

// stl_function_type 别名
template <typename F>
using stl_function_type = typename function_traits<std::remove_reference_t<F>>::stl_function_type;

// 可调用对象(函数,函数指针,静态函数,仿函数,std::bind,std::function)转stl函数
template <typename F>
stl_function_type<F> to_function(F const& f)
{
    return static_cast<stl_function_type<F>>(f);
}

template <typename F>
stl_function_type<F> to_function(F && f)
{
    return static_cast<stl_function_type<F>>(std::forward<F>(f));
}

#endif

测试代码

#include <iostream>
#include "function_traits.hpp"
using namespace std;

static void test_function_traits();

template <typename T>
void print() { cout << typeid(T).name() << endl; }

template <typename F>
void print_function_traits(F && f)
{
    using ft = function_traits<std::remove_reference_t<F>>;
    cout << "RT     " << typeid(ft::return_type).name() << endl;
    cout << "FT     " << typeid(ft::function_type).name() << endl;
    cout << "SFT    " << typeid(ft::stl_function_type).name() << endl;
    cout << "PT     " << typeid(ft::pointer).name() << endl;
    cout << "AT(0)  " << typeid(ft::type<0>).name() << endl;
    cout << "AT(1)  " << typeid(ft::type<1>).name() << endl;
}

int main()
{
    test_function_traits();
    return 0;
}

// 函数
void test01(int a, int b){
    cout << __FUNCTION__ << endl;
}

// 
struct Test02
{
    // 静态函数
    static void sf01(int a, int b) {
        cout << __FUNCTION__ << endl;
    }

    // 仿函数
    void operator()(int a, int b)
    {
        cout << __FUNCTION__ << endl;
    }

    // 成员函数
    void mf01(int a, int b)
    {
        cout << __FUNCTION__ << endl;
    }
};

static void test_function_traits()
{
    auto tf1 = to_function(test01);
    tf1(1,1);
    tf1 = to_function(Test02::sf01);
    tf1(1, 1);
    tf1 = to_function(Test02());
    tf1(1, 1);
    Test02 tt;
    tf1 = to_function([&tt](int a, int b) {cout << "----" << __FUNCTION__ << endl; tt.mf01(a, b); });
    tf1(1, 1);
    auto fb = std::bind(&Test02::mf01, tt, std::placeholders::_1, std::placeholders::_2);
    tf1 = to_function(fb);
    stl_function_type<decltype(tf1)> fr = fb;
    cout << "--------------" << endl;
    cout << typeid(fb).name() << endl;
    cout << typeid(fr).name() << endl;
    cout << "--------------" << endl;
    tf1 = to_function(fr);
    tf1(1, 1);
    print_function_traits(tf1);
}
posted @ 2020-03-14 11:13  一花一世界,一叶一乾坤  阅读(383)  评论(0编辑  收藏  举报