#include<functional>
#include<tuple>
#include<type_traits>
#include<iostream>
using namespace std;
template<typename T>
struct function_traits;
//处理普通函数
template<typename RET,typename ...ARGS>
struct function_traits<RET(ARGS...)>
{
constexpr static size_t arity = sizeof...(ARGS);
using function_type = RET(ARGS...);
using Ret_type = RET;
using stl_functional_type = std::function<function_type>;
using function_pointer = RET(*)(ARGS...);
template<size_t I>
struct ArgN
{
static_assert(I < arity, "failed!");
using type = std::tuple_element_t<I, std::tuple<ARGS...>>;
};
template<size_t I>
using ArgN_t = typename ArgN<I>::type;
};
//处理函数指针
template<typename RET, typename ...ARGS>
struct function_traits<RET(*)(ARGS...)> :function_traits<RET(ARGS...)> {
using function_type = RET(*)(ARGS...);
};
//处理std::function
template<typename RET, typename ...ARGS>
struct function_traits<std::function<RET(ARGS...)>> :function_traits<RET(ARGS...)> {
using function_type = std::function<RET(ARGS...)>;
};
/*
【使用可变参数宏实现,可变参数宏的列表...与宏定义中的__VA_ARGS__ 对应替换;而非与宏定义中的...对应替换】
可变参数为空:
假如定义了如下宏(不管是使用标准 C 方式还是 GNU C方式都可以,这里使用标准 C 的方式):
#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)
在标准 C 的环境下进行如下调用,可变参数为空:
eprintf("success!\n");
宏的扩展将会报错,因为扩展出来后的形式如下:
fprintf(stderr, "success!\n",);
fprintf 最后一个参数后面多了一个逗号,这样将报错。这种情况在标准 C 下无法解决,但是 GNU C可以解决。GNU C 赋予 "##" 另一种特殊意义(不是字符串连接的意义了),如果在可变参数前面加上"##",当可变参数为空时,前面的逗号会被删除:
#define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)
// 或者
#define eprintf(format, args...) fprintf(stderr, format, ##args)
当可变参数为空时,宏都会扩展成:
fprintf(stderr, "success!\n");
可以看到最后一个参数后面的逗号被删除了。
Clang 默认使用 GNU11,因此也支持这个功能。
*/
//处理成员函数
#define FUNCTION_TRAITS(...) \
template<typename RET, typename Class,typename ...ARGS> \
struct function_traits<RET(Class::*)(ARGS...)__VA_ARGS__> :function_traits<RET(ARGS...)> { \
using function_type = RET(Class::*)(ARGS...)__VA_ARGS__; \
protected: \
using logic_function_type= RET(ARGS...); \
};
FUNCTION_TRAITS()
FUNCTION_TRAITS(const)
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile)
//处理函数对象
template<typename Callable>
struct function_traits :function_traits<decltype(&Callable::operator())> {
using function_type =typename function_traits<Callable>::logic_function_type;//函数对象模拟成普通函数的类型
};
template<typename T>
void Print_Type()
{
std::cout << typeid(T).name() << std::endl;
}
int Print(int, double) { return 0; }
//函数对象
struct MyStruct
{
double Fn(char, char) const { return 0; }
char operator()(double, char*) {
return ' ';
}
};
int main()
{
auto fn = std::function<int(int, double)>(Print);
Print_Type<function_traits<decltype(fn)>::function_type>();
constexpr auto nargs = function_traits<decltype(Print)>::arity;
Print_Type<function_traits<decltype(Print)>::function_type>();
Print_Type<function_traits<decltype(&Print)>::function_type>();
Print_Type<function_traits<MyStruct>::function_type>();
Print_Type<function_traits<decltype(&MyStruct::Fn)>::function_type>();
using T = decltype(&MyStruct::Fn);
Print_Type<T>();
Print_Type<function_traits<decltype(Print)>::Ret_type>();
Print_Type<function_traits<decltype(Print)>::function_pointer>();
Print_Type<function_traits<decltype(Print)>::ArgN_t<1>>();
return 0;
}
C++组件扩展实现:函数特性function_traits
最新推荐文章于 2024-08-21 16:17:53 发布