c++11 function_typetraits备忘
function traits.
获取函数或成员函数的返回类型,参数类型,参数长度,类类型。
函数参数列表推断基于typelist:http://www.cnblogs.com/flytrace/p/3551414.html
先看一个普通函数非const的特化:
template<typename R, typename... Args>
struct function_traits<R (Args...)>
{
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
};
使用:
int testfunc1(char) { return 1; }
int main()
{
bool b;
b = std::is_same< typename function_traits<int(double)>::return_type, int>::value;
std::cout << "is same: " << b << std::endl;
b = std::is_same< typename function_traits<decltype(testfunc1)>::arg<0>::type, char>::value;
std::cout << "is same: " << b << std::endl;
}
对于各种参数类型的普通函数,都能正确推断。但重载函数的情形需要我们考虑。如下我们增加testfunc1的重载版本:
bool testfunc1(double, char) { return false; }
此时decltype(testfunc1)是无法编译通过的。这并不是我们的function_traits有问题。而是在没信息的情况下,decltype是无法选择testfunc1的重载版本的。除非我们在function_traits显式特化。
函数指针的function_traits也会遇到重载问题,如下是针对函数指针的function_traits:
template<typename R, typename... Args>
struct function_traits<R (*)(Args...)>
{
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
};
decltye(&testfunc1)也是无法编译通过的。很显然,你自己作为编译器作者的话,若是没有额外的信息,让你使用decltype去推断一个可重载的函数类型,你怎么能够知道用户希望得到哪个类型?除了显示特化以提供给编译器信息外,对于函数指针,我们还可以提前转换,显式给以类型信息供编译器推断,如下:
int (*castfunc)(char) = &testfunc1;
b = std::is_same< typename function_traits<decltype(castfunc)>::arg<0>::type, char>::value;
std::cout << "is same: " << b << std::endl;
castfunc1在定义时得到了testfunc1正确的重载类型,因此decltype在推断castfunc时就有了信息来选择正确的类型。
这并不是一个程序技术问题,更算是一个逻辑问题,就好像面对有多个定义的单词,没有上下文你是无法知道它要代表什么意思的。
这种显示转换并不会带给我们太多困扰。因为使用function_traits的场景,基本上是一种延迟推断手段。比如得到消息后,使用泛型手法分发消息处理。而消息处理函数我们在注册的时候肯定是知道函数类型的,在注册时我们就已经可以显示转换这个函数指针而不会遇到重载问题了。直接使用decltype(testfunc1)好像在我们测试function_traits时才会遇到,嗯,另一个人也遇到了,不然我不会试验。。。
然而确实存在一个可能,使我们可以传入testfunc1,而不用给予完整类型信息,虽然不适用于function_traits的情况。如下:
template<typename ...Args>
struct OverloadResolved
{
template<typename R>
static auto static_doit( R (*f) (Args...), Args ... args ) -> R { return f(args...);}
}; template<typename ...Args>
auto deduce(Args...) -> OverloadResolved<Args...> { return OverloadResolved<Args...>(); } template<typename T>
struct dummy : public T { }; #define doit(f, ...) ( dummy<decltype(deduce( __VA_ARGS__ ))> :: static_doit(f, __VA_ARGS__) )
使用:
char aa = 'a'; double ff = 0.1;
std::cout << doit(testfunc1, aa) << " " << doit(testfunc1, ff, aa) << std::endl;
可以看到,虽然testfunc1有2个重载版本,但仍能正确的执行testfunc1(aa)和testfunc1(ff, aa).
当然因为此处给出了参数信息。这是一个运行时方案,而function_traits要求我们在编译期就推断。
以下添加类成员函数的function_traits:
template <typename R, typename T, typename... Args>
struct function_traits<R (T::*)(Args...)>
{
typedef T class_type;
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
};
还需要添加const,volatile修饰符的。以下是更完整的版本:
template<typename T>
struct function_traits; template<typename R, typename... Args>
struct function_traits<R (Args...)>
{
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template<typename R, typename... Args>
struct function_traits<R (Args...) const>
{
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template<typename R, typename... Args>
struct function_traits<R (Args...) volatile>
{
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template<typename R, typename... Args>
struct function_traits<R (Args...) const volatile>
{
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template<typename R, typename... Args>
struct function_traits<R (*)(Args...)>
{
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template <typename R, typename T, typename... Args>
struct function_traits<R (T::*)(Args...)>
{
typedef T class_type;
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template <typename R, typename T, typename... Args>
struct function_traits<R (T::*)(Args...) const>
{
typedef T class_type;
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template <typename R, typename T, typename... Args>
struct function_traits<R (T::*)(Args...) volatile>
{
typedef T class_type;
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
}; template <typename R, typename T, typename... Args>
struct function_traits<R (T::*)(Args...) const volatile>
{
typedef T class_type;
typedef R return_type;
typedef typelist<Args...> arglist;
enum { arg_count = sizeof...(Args) };
template<unsigned int N>
struct arg
{
typedef typename at<N, arglist>::type type;
};
};
c++11 function_typetraits备忘的更多相关文章
- opencv-2.4.11编译备忘
编译完成后,想测试example中例子,但是由于没有sudo权限,不能运行pkg-config查看opencv的--cflags和--libs. 记录一下,备忘: pkg-config --libs ...
- 11. 星际争霸之php设计模式--备忘模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- Nmap备忘单:从探索到漏洞利用(Part 2)
这是我们的第二期NMAP备忘单(第一期在此).基本上,我们将讨论一些高级NMAP扫描的技术,我们将进行一个中间人攻击(MITM).现在,游戏开始了. TCP SYN扫描 SYN扫描是默认的且最流行的扫 ...
- [原]TCP/UDP使用细节备忘
body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...
- HTML5终极备忘大全
二.文字备忘之标签 HTML5中新增的标签 <article> 定义文章 <aside> 定义页面内容旁边的内容 <audio> 定义声音内容 <canvas ...
- [转] HTML5终极备忘大全(图片版+文字版)---张鑫旭
by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1544 一.前言兼图片 ...
- Linq to XML 读取XML 备忘笔记
本文转载:http://www.cnblogs.com/infozero/archive/2010/07/13/1776383.html Linq to XML 读取XML 备忘笔记 最近一个项目中有 ...
- Python中利用函数装饰器实现备忘功能
Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下 " ...
- 基于Prism.Windows的UWP开发备忘
以前做UWP开发都是使用MvvmLight,主要是简单易上手,同时也写了很多MvvmLight的开发系列文章: UWP开发必备以及常用知识点总结 UWP开发之Mvvmlight实践九:基于MVVM的项 ...
随机推荐
- 『TensorFlow』SSD源码学习_其二:基于VGG的SSD网络前向架构
Fork版本项目地址:SSD 参考自集智专栏 一.SSD基础 在分类器基础之上想要识别物体,实质就是 用分类器扫描整张图像,定位特征位置 .这里的关键就是用什么算法扫描,比如可以将图片分成若干网格,用 ...
- 数据分析库之matplotlib
一.Matplotlib基础知识 Matplotlib中的基本图表包括的元素 x轴和y轴 axis 水平和垂直的轴线 轴标签 axisLabel 水平和垂直的轴标签 x轴和y轴刻度 tick 刻度标示 ...
- mongoose手动生成ObjectId
用mongoose驱动保存数据,如果_id没有定义,那么在save的时候,mongoose驱动会自己生成一个_id.那么如果需要手动生成可以用mongoose.Types.ObjectId()方法. ...
- 1.3 第一个Go程序
1.3.1 Hello Go // hello.go package main import ( "fmt" ) func main() { fmt.Println("H ...
- C++ 多目录多文件编译 技巧
http://www.cplusplus.com/forum/articles/10627/ 1.hpp文件 hpp文件可以使用template函数和class静态函数(不含静态成员) a)不可包含全 ...
- C# MVC 微信支付教程系列之公众号支付
微信支付教程系列之公众号支付 今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后 ...
- mybaties逆向工程教程工具
http://www.cnblogs.com/wangkeai/p/6934683.html
- SVG路径PATH
SVG路径PATH 在使用之前建议下个PS或者FLASH玩玩里面的钢笔工具(FLASH里的钢笔工具比PS里的好用) PATH用到的指令: M----(X Y):移动到 Z----(none):关闭路径 ...
- JAVA数据库操作回滚小结
一:总结的原因 在最近的工作中,遇到了一个一对多关系多表数据传输,传送成功状态绑定在主数据表上,因为代码不健壮问题造成了主表传送状态更新失败,而子表数据就被重复插入.又由于数据传输频率很高,我们的测试 ...
- ADO.NET之SqlConnection、sqlcommand的应用(学习笔记)
一.知识描述点 1.SqlConnection (1)使用SqlConnection类可以连接到SQL Server数据库.SqlConnection对象的主要属性和方法如下: ——属性:Connec ...