函数的类型主要集中在以下几种

  • 函数指针
  • 函数对象,是一个类对象,内部重载的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) consttraits_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


完整代码请参考这里

C++代码片段(一)萃取函数返回值类型,参数类型,参数个数相关推荐

  1. 【C 语言】C 项目开发代码规范 ( 形参合法性判断 | 函数返回值局部变量 | 函数中不用全局变量 | 函数中使用局部变量接收形参 | 函数返回值 | 形参作返回值 | 形参返回值处理 )

    文章目录 一.C 项目开发代码规范 一.C 项目开发代码规范 上一篇博客 [C 语言]字符串模型 ( 键值对模型 ) 中 , 完成了字符串的 键值对 查找功能 , 代码不太规范 ; C 项目开发代码规 ...

  2. 函数返回值为指针类型的总结

    参考博客:https://blog.csdn.net/zxccaoya/article/details/53468500 char*GetString(void) {char p[]= "h ...

  3. typescript 数据类型、函数返回值、类型断言、联合类型、类型兼容

    null和undefined类型:是所有类型的子类型,即可以将任意类型赋值为二者any类型:可以赋值任何类型unknown类型:引入的顶级类型unknown,对照于any,unknown是类型安全的, ...

  4. c语言函数返回值可以是字符串吗,函数返回值可以是字符串吗

    c语言中函数返回值可以是数组.字符串和结构体吗? 因为在C语言中函数不能返回数组,但字符串是存储在字符数组中的,所以能C语言中实现函数返回字符串,首先要确定函数返回的字符串地址的来源,一般分为四种方式 ...

  5. 2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码)

    2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码) 1.引用(普通引用) 变量 ...

  6. C语言100题第二题 编写函数fun()的功能并调用:从3个红球,5个白球,6个黑球中任意取8个 作为一组,进行输出。在每组中,可以没有黑球,但是必须有红球和白球。组合数作为函数返回值。

    结构:分析-代码-总结 原题 分析 代码 总结 原题 编写函数fun()的功能并调用:从3个红球,5个白球,6个黑球中任意取8个 作为一组,进行输出.在每组中,可以没有黑球,但是必须有红球和白球.组合 ...

  7. python返回值return用法_Python中return函数返回值代码实例用法

    本篇文章小编给大家分享一下Python中return函数返回值代码实例用法,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. return 添加返回值 r ...

  8. python函数的用法详解(作用、定义、调用、函数参数、函数返回值、函数说明文档、函数嵌套使用)

    1. 函数的作⽤ 函数就是将⼀段具有独⽴功能的代码块整合到⼀个整体并命名,在需要的位置调⽤这个名称即可完成对应的需求. 函数在开发过程中,可以更⾼效的实现代码重⽤. 2. 函数的使⽤步骤 2.1 定义 ...

  9. go函数详解:函数定义、形参、返回值定义规范、函数内存分析、不支持重载、支持可变参数、基本数据类型和数组默认都是值传递的、支持自定义数据类型、函数返回值命名

    引入 [1]为什么要使用函数: 提高代码的复用型,减少代码的冗余,代码的维护性也提高了 [2]函数的定义: 为完成某一功能的程序指令(语句)的集合,称为函数. [3]基本语法 func 函数名(形参列 ...

最新文章

  1. MindSpore基准性能
  2. spring in action 4 线路图
  3. java common http_httpClient和common-httpclient的区别
  4. UVA 10746 Crime Wave - The Sequel
  5. stateful openflow------整理openstate原理以及具体应用
  6. iOS 9音频应用播放音频之ios9音频基本功能
  7. java 单链表约瑟夫环_java循环单链表实现约瑟夫环问题
  8. Ajax框架DWR入门
  9. [推荐]大量 Blazor 学习资源(二)
  10. 分布式 知乎 github_如何使用GitHub本机功能来帮助管理中型分布式团队
  11. CNN中全连接层是什么样的
  12. Java 设计模式之中介者模式
  13. 手机可以和linux数据互传吗,没网络也可以传输数据?OPPO互传与HUAWEI Share实测体验...
  14. 没有人更比他懂基金业务:博格和他的先锋集团创业史(4):
  15. OpenCV2:Mat属性type,depth,step
  16. GAN的目标函数(F散度;KL散度;JS散度;Pearson \chi^2 散度;IPM;Wasserstein距离;MMD)
  17. 你在用FastReport.Net报表工具做报表没
  18. pythonlambda多行_Python中通过lambda抛异常的奇迹淫巧
  19. APK文件的安装方法
  20. 全国哀悼日 网站变灰装(附代码)

热门文章

  1. python json解析方法_Python 中的 JSON 方式讲解
  2. php提交飞信,php发送飞信消息
  3. 第一阶段冲刺第五天天
  4. 抽象类、抽象方法与代码块
  5. iOS ----------怎么修改xcode默认打开方式
  6. [转]正确配置Linux系统ulimit值的方法
  7. 4.编程打印一个二维数组中所有元素的和,并打印最大值,最小值(以及它们所在的行号和列号)
  8. 位移运算符(7个)之第一个: 左移
  9. Web服务器漏洞和安全
  10. [Python学习] 专题三.字符串的基础知识