zoukankan      html  css  js  c++  java
  • C++利用不完全实例化来获得函数模板参数的返回值和参数

    有一些模板会以函数为模板参数,有时候这些模板要获得函数的返回值和参数。如在boost中的signal和slot机制,就存在这样情况。

    那么,我们如何得到这些信息呢?

    我们使用C++不完全实例化来实现。


    比如,有这个代码

    typedef function_traits<void (int,const char*)> Signal;

    能够得到Signal::result_type == void, Signal::arg1_type == int, Signal::arg2_type == const char*?


    要想获得这种效果,必须通过Function的指针来实现,我们借助一个function_traits_help模板来实现。

    template<typename Function>
    struct function_traits : public function_traits_help<Function*>
    {
    };
    


    function_traits_help类接受Function的指针为参数。

    函数类型和函数指针是不一样的,如

    void (int,int)//定义一个函数类型
    void (*)(int, int) //定义了一个函数指针
    
    template<typename Func>
    struct FuncType {
       typedef FuncPtr funcPtr;
    };
    FuncType<void(int,int)>::funcPtr 等同于 void(*)(int,int)


    function_traits_help就是利用不完全实例化来实现

    首先,定义主模板

    template<typename FunctionPtr> struct function_traits_help;

    主模板不做任何事情,作为一个核心模板存在,但从不使用,因此无需具体定义。


    定义无参数的实现

    template<typename R>
    struct function_traits_help<R(*)(void)>
    {
    	enum {arty = 0 };
    	typedef R result_type;
    };

    function_traits_help<R(*)(void)>就是function_traits_help<FunctionPtr>的一种具体实例化,C++编译器当遇到 R (*)(void)这样类型的函数指针类型的时候,就会匹配到这个定义上。


    定义包含一个参数的模板

    template<typename R, typename T1>
    struct function_traits_help<R(*)(T1)>
    {
    	enum {arty = 1 };
    	typedef R result_type;
    	typedef T1 arg1_type;
    };
    

    同样的,C++编译器遇到 R (*)(T1)类型的函数指针时,就会匹配到这个定义。


    同理,我们可以定义2,3,4,...

    template<typename R, typename T1, typename T2>
    struct function_traits_help<R(*)(T1, T2)>
    {
    	enum {arty = 2 };
    	typedef R result_type;
    	typedef T1 arg1_type;
    	typedef T2 arg2_type;
    };
    
    template<typename R, typename T1, typename T2, typename T3>
    struct function_traits_help<R(*)(T1, T2, T3)>
    {
    	enum {arty = 3 };
    	typedef R result_type;
    	typedef T1 arg1_type;
    	typedef T2 arg2_type;
    	typedef T3 arg3_type;
    };
    
    template<typename R, typename T1, typename T2, typename T3, typename T4>
    struct function_traits_help<R(*)(T1, T2, T3, T4)>
    {
    	enum {arty = 4 };
    	typedef R result_type;
    	typedef T1 arg1_type;
    	typedef T2 arg2_type;
    	typedef T3 arg3_type;
    	typedef T4 arg4_type;
    };
    
    ..............


    这样,我们就可以得到正确的信息:

    typedef function_traits<int (int,char*)> Function;
    

    于是:

    Function::arty  : 2;

    Function::result_type : int

    Function::arg1_type : int

    Function::arg2_type : char* 



    我们还可以用typeid(x).name()来看真正的效果。

    PS: 要使用typeid(x).name()要首先  #include <typeinfo>


    template<typename T>
    void show_function_info(const char* name)
    {
    	printf("%s: arg count=%d, result_type:%s
    ", name, T::arty, typeid(typename T::result_type).name());
    	show_args<T::arty, T> x;
    	x();
    }

    show_args<T::arty, T>也是一个不完全实例化的对象,用于匹配正确数目参数的对象。

    show_args的定义如下:

    template<int N, typename Func>
    struct show_args; //主模板,从不使用
    
    template<typename Func>
    struct show_args<0, Func> { //0个参数
    	void operator()(){ }
    };
    
    template<typename Func>
    struct show_args<1, Func> {//1个参数
    	void operator()(){ 
    		printf("	arg1 = %s
    ", typeid(typename Func::arg1_type).name());
    	}
    };
    
    template<typename Func>
    struct show_args<2, Func> {//2个参数
    	void operator()(){
    		printf("	arg1 = %s
    ", typeid(typename Func::arg1_type).name());
    		printf("	arg2 = %s
    ", typeid(typename Func::arg2_type).name());
    	}
    };
    
    template<typename Func>
    struct show_args<3, Func> {
    	void operator()(){
    		printf("	arg1 = %s
    ", typeid(typename Func::arg1_type).name());
    		printf("	arg2 = %s
    ", typeid(typename Func::arg2_type).name());
    		printf("	arg3 = %s
    ", typeid(typename Func::arg3_type).name());
    	}
    };
    
    template<typename Func>
    struct show_args<4, Func> {
    	void operator()(){
    		printf("	arg1 = %s
    ", typeid(typename Func::arg1_type).name());
    		printf("	arg2 = %s
    ", typeid(typename Func::arg2_type).name());
    		printf("	arg3 = %s
    ", typeid(typename Func::arg3_type).name());
    		printf("	arg4 = %s
    ", typeid(typename Func::arg4_type).name());
    	}
    };
    
    .................................


    最后,用宏来简化实现

    #define SHOW_FUNC(T) 
    	show_function_info<T  > (#T)


    最后的测试代码

    int main()
    {
    	SHOW_FUNC(function_traits<int ()>);
    	SHOW_FUNC(function_traits<void ()>);
    	SHOW_FUNC(function_traits<void (int)>);
    	SHOW_FUNC(function_traits<int (int,char*)>);
    	SHOW_FUNC(function_traits<int (int,char*, double)>);
    
    };
    


    该程序的运行结果是

    function_traits<int ()>: arg count=0, result_type:i
    function_traits<void ()>: arg count=0, result_type:v
    function_traits<void (int)>: arg count=1, result_type:v
    	arg1 = i
    function_traits<int (int,char*)>: arg count=2, result_type:i
    	arg1 = i
    	arg2 = Pc
    function_traits<int (int,char*, double)>: arg count=3, result_type:i
    	arg1 = i
    	arg2 = Pc
    	arg3 = d
    




  • 相关阅读:
    Gym 100418J Lucky tickets(数位dp)
    UI各种小控件的用法
    安卓系统底层C语言算法之測试參数是几个long型的算法
    Chisel Tutorial(一)——Chisel介绍
    java中super的作用
    flume採集数据导入elasticsearch 配置
    UML中的序列图(时序图)
    简单的Queue
    UNIX环境高级编程(5):文件I/O(1)
    四、基于HTTPS协议的12306抢票软件设计与实现--水平DNS并发查询分享
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3190267.html
Copyright © 2011-2022 走看看