zoukankan      html  css  js  c++  java
  • [C++] 特殊用途语言特性

    三种函数相关的语言特性:默认实参、内联函数、constexpr函数

    默认实参

    某些函数有这样一些形参,在函数的很多次调用中它们都被赋予一个相同的值,此时,我们把这个反复出现的值称为函数的默认实参。调用含有默认实参的函数时,可以包含该实参,也可以忽略该实参。

    typedef string::size_type sz;
    string screen(sz ht = 24, sz wid = 80, char backgrnd = ' ');

    其中我们为每个形参都提供了默认实参,默认实参作为形参的初始值出现在形参列表中。

    我们可以为一个或多个形参定义默认值,

    需要注意的是:一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。

    使用默认形参调用函数

    如果我们想使用默认形参,只要在调用函数的时候忽略该实参就可以了。

    函数调用时实参按其位置解析,默认实参负责填补函数调用缺少的尾部实参(靠右侧位置)。如果想要覆盖backgrad的默认值,必须先为ht和wid提供实参。

    所以在设计默认实参的函数时,应该合理设置形参的顺序,尽量让不怎么使用默认值的形参出现在前面,而让那些经常使用默认值的形参出现在后面。

    默认实参声明

    对于一个函数声明,通常的习惯就是将它放在头文件中,并且一个函数只声明一次,但是多次声明同一个函数也是合法的。

    在给定的作用域中一个形参只能被赋予一次默认实参,换句话说,函数的后续声明只能为之前那些没有默认值的形参添加默认实参,而且该形参右侧的所有形参必须都有默认值。

    string screen(sz, sz, char = ' ');
    // 表示高度和宽度的形参没有默认值
    string screen(sz, sz, char = '*');
    // 错误,重复声明,不能修改一个已经存在的默认值
    string screen(sz = 24, sz = 80, char);
    // 正确,添加默认实参

    通常应该在函数声明中指定默认实参,并将该声明放在合适的头文件中。

    默认实参初始值

    局部变量不能作为默认实参,除此之外,只要表达式的类型能转换为形参所需的类型,该表达式就能作为默认实参

    // wd def ht的声明必须在函数之外
    sz wd = 80;
    char def = ' ';
    sz ht();
    string screen(sz = ht(), sz = wd, char = def);

    string window = screen();
    // 调用screen(ht(), 80, ' ');

    用作默认实参的名字在函数所在作用于内解析,而这些名字的求值过程发生在函数调用时

    void f2() {
        def = '*';
        // 改变了默认实参值
        sz wd = 100;
        // 隐藏了外部定义的wd,但是没有改变实参值。
        window = screen();
    }
    // 调用 screen(ht(), 80, '*');

    f2内部改变了def值,所以对screen的调用会传递这个更新过的值,

    虽然我们函数还声明了一个局部变量用于隐藏外部的wd,但是该局部变量与传递给screen的默认实参没有任何关系。

    内联函数

    把函数指定为内联函数,通常就是将它在每个调用点上“内联地”展开。避免函数调用的开销

    举个例子

    inline const string& shorterString(const string& s1, const string& s2) {
        return s1.size() <= s2.size() ? s1 : s2;
    }
    
    cout << shorterString(s1, s2) << endl;
    // 该调用在编译过程中展开成类似于下面的形式
    cout << (s1.size() <= s2.size() ? s1 : s2) << endl;

    内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求

    constexpr函数

    constexpr函数是指能用于常量表达式的函数。

    需要遵循以下几项约定:

    1、函数的返回类型及所有形参的类型都得是字面值类型

    2、函数体中必须有且只有一条return语句

    3、函数提可以包含其他的语句,但是这些语句不能在运行期起作用

    4、函数可以不返回常量,但是在调用的时候实参必须传入常量表达式

    constexpr int new_sz() { return 42; }
    constexpr int foo = new_sz();

    new_sz()无参数,返回值是常量表达式。

    new_sz()可以初始化constexpr类型的变量foo

    在编译时constexpr函数被隐式指定为内联函数

    constexpr返回值并非一个常量

    // 如果arg是常量表达式,则scale(arg)也是常量表达式
    constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }
    
    int arr[scale(2)];
    // 正确、scale(2)是一个常量表达式
    int i = 2;
    int a2[scale(i)];
    // 错误、scale(i)不是一个常量表达式
  • 相关阅读:
    Jedis scan及其count的值
    redis中KEYS、SMEMBERS、SCAN 、SSCAN 的区别
    Windows环境下RabbitMQ的启动和停止命令
    HTTP状态码->HTTP Status Code
    给所有的input trim去空格
    git clone 使用用户名和密码
    ABA问题
    FIFO、LRU、LFU的含义和原理
    【phpstorm】破解安装
    【windows7】解决IIS 80端口占用问题(亲测)
  • 原文地址:https://www.cnblogs.com/immjc/p/8183718.html
Copyright © 2011-2022 走看看