?!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
获取函数或成员函数的q回cdQ参数类型,参数长度Q类cd?/p>
函数参数列表推断ZtypelistQhttp://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;
};
};
复制代码
使用Q?/p>
复制代码
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;
}
复制代码
对于各种参数cd的普通函敎ͼ都能正确推断。但重蝲函数的情形需要我们考虑。如下我们增加testfunc1的重载版本:
bool testfunc1(double, char) { return false; }
此时decltype(testfunc1)是无法编译通过的。这q不是我们的function_traits有问题。而是在没信息的情况下Qdecltype是无法选择testfunc1的重载版本的。除非我们在function_traits昑ּ特化?/p>
函数指针的function_traits也会遇到重蝲问题,如下是针对函数指针的function_traitsQ?/p>
复制代码
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)也是无法~译通过的。很昄Q你自己作ؓ~译器作者的话,若是没有额外的信息,让你使用decltypeL断一个可重蝲的函数类型,你怎么能够知道用户希望得到哪个cdQ除了显C特化以提供l编译器信息外,对于函数指针Q我们还可以提前转换Q显式给以类型信息供~译器推断,如下Q?/p>
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时就有了信息来选择正确的类型?/p>
qƈ不是一个程序技术问题,更算是一个逻辑问题Q就好像面对有多个定义的单词Q没有上下文你是无法知道它要代表什么意思的?/p>
q种昄转换q不会带l我们太多困扰。因Z用function_traits的场景,基本上是一Ugq推断手Dc比如得到消息后Q用泛型手法分发消息处理。而消息处理函数我们在注册的时候肯定是知道函数cd的,在注册时我们已l可以显C{换这个函数指针而不会遇到重载问题了。直接用decltype(testfunc1)好像在我们测试function_traits时才会遇刎ͼ嗯,另一个h也遇CQ不然我不会试验。。?/p>
然而确实存在一个可能,使我们可以传入testfunc1Q而不用给予完整类型信息,虽然不适用于function_traits的情c如下:
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__) )
复制代码
使用Q?/p>
char aa = 'a'; double ff = 0.1;
std::cout << doit(testfunc1, aa) << " " << doit(testfunc1, ff, aa) << std::endl;
可以看到Q虽然testfunc1?个重载版本,但仍能正的执行testfunc1(aa)和testfunc1(ff, aa).
当然因ؓ此处l出了参C息。这是一个运行时ҎQ而function_traits要求我们在编译期推断?/p>
以下dcL员函数的function_traitsQ?/p>
复制代码
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;
};
};
复制代码
q需要添加constQvolatile修饰W的。以下是更完整的版本Q?br style="margin: 0px; padding: 0px;"/>
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;
};
};