zoukankan      html  css  js  c++  java
  • 省略号和可变参数模板

    1.基本概念

      省略号在C/C++中有很多用途,包括函数的变量参数列表。C运行库的printf()就是常见示例。

    可变参数模板提供了类型安全和灵活性,可应用于类模板和函数模板。

    2.语法示例

    template<typename ... args>

    可变参数模板可以有0个或多个参数,如果要求至少一个参数:

    template<typename one,typename... rest> class classname;

    可变参数模板函数示例:

    template<typename... Args> returnType fun(Args... args);             //参数按值传递
    templata<typename... Args> returnType fun(Args&... args);            //参数引用传递
    templata<typename... Args> returnType fun(Args*... args);            //参数为指针类型
    templata<typename... Args> returnType fun(const Args&... args);      //常量引用
    templata<typename one,typename... Args> returnType fun(const one& arg1,const Args&... args); //需要至少一个参数

     程序示例:

    template<typename... Arguments>  
    void tfunc(const Arguments&... args)  
    {  
        const unsigned numargs = sizeof...(Arguments);  
      
        X xobj[numargs]; // array of some previously defined type X  
      
        helper_func(xobj, args...);  
    }  

    3. C中的省略号

      在C中使用省略号显得比较麻烦,示例如下:

    #include <stdio.h>
    #include <stdarg.h>
    
    void test(int a,...); 
    
    int main(){
        
        test(1, 2, 3, 4);
        return 0;
    }
    void test(int a,...)
    {
        va_list args;
        int nArg = a; //a作为固定参数,用来确定变参的起始地址
        va_start(args, a);
        printf("%d\n", va_arg(args,int));
        printf("%d\n", va_arg(args, int));
        printf("%d\n", va_arg(args, int));
        va_end(args);
        
    }

      其中test函数是个简单的示例,在C中使用省略号必须要有一个指定参数(第一位参数),不能只有省略号。由于函数的参数入栈是从右往左入的,栈的生长是从高地址向低地址生长,所以在参数最左(第一位参数)指定参数就方便确定可变参数的地址了 ,不然没法取得可变参数。

      接下来va_list是指向参数的指针,在vadefs.h中定义如下:

    typedef char *  va_list;

      然后看一下va_start的定义:

    #define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

      从该定义中可以看出来args指向了第二个参数2

      然后下一句是执行了va_arg(args,int),然后打印

      看一下它的定义

    #define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

      这句话是将args指向了下一个参数,但是输出的是下一个参数的上一个:( -_INTSIZEOF(t)),这样可以从第二个参数开始,因为va_start已经将args指向了第二个参数,如果不( -_INTSIZEOF(t))的话会跳过第二个,因为args是持续累加的,所以下面的va_arg(args,int)会连续指向第三个参数、第四个......

      然后最后的va_end(args)是释放args的指向

    #define _crt_va_end(ap)      ( ap = (va_list)0 )

      但是使用va_arg的话会一直指向下一个,由于不知道参数的个数,早晚会内存溢出,这个问题还不太懂,留坑。。。

    ------------ 转载请注明出处 ------------
  • 相关阅读:
    sql 日期格式化 比较全面
    SQL Server 2005 中的树形数据处理示例1
    Web网站的性能测试工具
    js实现时分秒
    sql查询远程数据库的表的数据并填充到本地数据库的表
    Windows 2003操作系统十四招加速大法
    window2003 server的一些优化设置_windows 2003
    解决html向aspx页面传值汉字乱码问题
    js快捷键大全 http://www.zhangxinxu.com/wordpress/?p=1667
    iis 重启命令
  • 原文地址:https://www.cnblogs.com/whlook/p/6478536.html
Copyright © 2011-2022 走看看