c++11 function_typetraits备忘
2014-02-26 03:15
369 查看
function traits.
获取函数或成员函数的返回类型,参数类型,参数长度,类类型。
函数参数列表推断基于typelist:/article/6024664.html
先看一个普通函数非const的特化:
使用:
对于各种参数类型的普通函数,都能正确推断。但重载函数的情形需要我们考虑。如下我们增加testfunc1的重载版本:
此时decltype(testfunc1)是无法编译通过的。这并不是我们的function_traits有问题。而是在没信息的情况下,decltype是无法选择testfunc1的重载版本的。除非我们在function_traits显式特化。
函数指针的function_traits也会遇到重载问题,如下是针对函数指针的function_traits:
decltye(&testfunc1)也是无法编译通过的。很显然,你自己作为编译器作者的话,若是没有额外的信息,让你使用decltype去推断一个可重载的函数类型,你怎么能够知道用户希望得到哪个类型?除了显示特化以提供给编译器信息外,对于函数指针,我们还可以提前转换,显式给以类型信息供编译器推断,如下:
castfunc1在定义时得到了testfunc1正确的重载类型,因此decltype在推断castfunc时就有了信息来选择正确的类型。
这并不是一个程序技术问题,更算是一个逻辑问题,就好像面对有多个定义的单词,没有上下文你是无法知道它要代表什么意思的。
这种显示转换并不会带给我们太多困扰。因为使用function_traits的场景,基本上是一种延迟推断手段。比如得到消息后,使用泛型手法分发消息处理。而消息处理函数我们在注册的时候肯定是知道函数类型的,在注册时我们就已经可以显示转换这个函数指针而不会遇到重载问题了。直接使用decltype(testfunc1)好像在我们测试function_traits时才会遇到,嗯,另一个人也遇到了,不然我不会试验。。。
然而确实存在一个可能,使我们可以传入testfunc1,而不用给予完整类型信息,虽然不适用于function_traits的情况。如下:
http://stackoverflow.com/questions/9054703/overloaded-function-as-argument-of-variadic-template-function
使用:
可以看到,虽然testfunc1有2个重载版本,但仍能正确的执行testfunc1(aa)和testfunc1(ff, aa).
当然因为此处给出了参数信息。这是一个运行时方案,而function_traits要求我们在编译期就推断。
以下添加类成员函数的function_traits:
还需要添加const,volatile修饰符的。以下是更完整的版本:
View Code
获取函数或成员函数的返回类型,参数类型,参数长度,类类型。
函数参数列表推断基于typelist:/article/6024664.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的情况。如下:
http://stackoverflow.com/questions/9054703/overloaded-function-as-argument-of-variadic-template-function
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;
};
};
View Code
相关文章推荐
- 哈希表hash table
- C++按值返回、按址返回、按别名返回开销的区别
- C++迭代器和标准库算法的注意事项——个人笔记
- c语言:将二进制数按位输出
- STL中用next_permutation解决排列问题
- Eclipse C++
- 10个足以让你成为更优秀的程序员的C语言资源
- c++ 学习笔记----头文件
- 递归算法巧解字符串问题
- C++读写文件笔记
- C++文件操作详解(ifstream、ofstream、fstream)
- C++学习之运算符重载的总结
- C++学习之运算符重载的总结
- C语言的内存分配(参考)
- 纸上谈兵(C++):字符串的使用
- VC++调用大漠插件的方法
- C++ string 用法详解
- c++项目包含c头文件 .c文件时的编译
- [面试算法]有一无符号整型数组,大小为10, 初始的数值随机,但在[0, 99]之间。请用C语言写一个过滤程序,令数组内的数据互不相等。
- 详细讲解C++ 类的继承