C++ constexpr

constexpr是C++的修饰词,用于指定"编译期可以求数值的常量表达式",可用于修饰变量,函数,类/结构体,构造函数/析构函数,模板五种情况,作用就是支持编译期常量处理。constexpr的实际应用中最常用的是修饰变量和函数。

  • constexpr用于修饰变量,可以构建真常量,即编译器常量。
  • constexpr用于修饰函数,可以用于编译期求值;
  • constexpr用于修饰类/结构体。可以用来在编译期构造对象;
  • constexpr用于修饰构造函数/析构函数,可以在编译器就对类对象进行初始化/销毁;
  • constexpr用于修饰模板,在编译期间完成模板实例化进行求数值。

增加编译期间求解的效果是提升性能、增强类型安全。

实例1------constexpr修饰变量:

C++ 复制代码
#include <iostream>
constexpr int MAXsize = 100; // 由constexptr修饰的int型真常量,
//在编译期就可以通过直接赋值确定取值为100.
constexpr int OVERsize = MAXsize + 50;
//在编译期可以通过计算得到确定取值为150.
//由constexpr修饰的MAXsize和OVERsize两个真常量,分别取值100和150.
//编译正常。符合处理直觉。

提问: constexpr 可以修饰变量,此时该变量是编译期常量(值必须在编译期确定,且生命周期内不可修改,比 const 更严格)如果这个变量的取值在编译期间没有确定会报错吗?还是任意给这个变量取定一个随机值?取定随机值会导致这个变量实际没有可用效果? 以及这里讲的生命周期不可修改是什么意思?一个constexpr修饰的真常量的生命周期不就是整个程序运行的期间都有效吗?编译期常量即真常量是不占用C++堆内存和栈内存的吧!

arduino 复制代码
解答:
// constexpr 修饰变量,这个变量的数值必须在编译期确定,生命周期内不可修改。
// 如果编译期间这个变量的数值没有确定指定,会直接编译报错,无随机值。
// constexpr 修饰得到的真常量在生命周期内都只具有只读属性,不可修改。
// constexpr 修饰得到的真常量的生命周期取决于变量定义所在的作用域决定。
    // 即constexpr只负责跟编译器通力合作在编译期间确定数值。
    // 至于这个真常量在何时失效取决于这个变量的自身的作用域,
    // 即定义在函数内部的变量,即便加上constexpr修饰,
    // 这个真常量的生命周期依然只在函数内的局部作用域效果下。constexpr修饰的真常量被存储在静态只读数据区。

总结1:

  • constexpr修饰变量,得到真常量,存储在静态存储区,不占用运行内存;(因此增强性能)
  • constexpr修饰得到的真常量,如果没有在编译期指定,直接报错。
  • constexpr修饰得到的真常量,生命周期内权限为只读,不可修改。
  • constexpr修饰得到的真常量,生命周期长度取决于变量本身的生命周期。

实例2------constexpr修饰函数:

表示这个函数,如果入参是编译期常量,在编译期完成计算得到处理结果。如果入参不是编译期间常量,那就退化成普通函数。两种情况都不会报错。UDL和普通函数都支持这种退化兼容。

C++ 复制代码
//constexpr修饰UDL(自定义字面值运算符)
constexpr long long operator "" _KM2m(long long kilometer) {
    return kilometer*1000;
}
//constexpr修饰普通函数
constexpr int add(int a, int b){
    return a + b;
}

实例3------constexpr修饰类/结构体:

作用是在编译期构造类对象,即编译期常量对象。 要求:

  • 类的构造函数必须是constexpr构造函数;
  • 编译期内需调用的成员函数也必须有constexpr修饰;
  • 类的成员变量中,对于被constexpr使用/依赖的静态成员变量,必须在类内constexpr修饰。而且最好直接用static constexpr
C++ 复制代码
//constexpr修饰结构体(在C++中将结构体视为类的一种)
struct Point{

    //constexpr 修饰构造函数
    constexpr Point(int x_, int y_) : x(x_), y(y_) {}
        // C++中约定俗成用 变量名右加下划线 表示类成员变量的命名。
        // x(x_), y(y_) 是 C++ 中的「成员初始化列表(Member Initialization List)
            // 效果是将x_,y_的值对应赋值给x,y
            // `x(x_)` 和 `x=x_` 在初始化列表中等价
            
    //constexpr 修饰构造函数
    constexpr int get_x() const {
        return}
    }
    
    int x;
    int y;
   }
   
   int main () {
       //编译器构造Ponit对象
       constexpr Point p0(10,20);
       //编译期调用成员函数,获取数值
       constexpr int x_val = p0.get_x(); 
       return 0;
   }
  • 非静态成员变量是指属于单个对象的变量,每个对象独一份,生命周期随对象变化;
  • 静态成员变量属于类本身的,所有对象共享一份,生命周期贯穿程序。
    • 静态const成员变量:类内直接初始化,因为贯穿程序的生命周期,且在运行期间数值不可修改,是绑定在整个类上的变量。static const 变量类型 变量名 = 初始化数值;
      • static constexpr 变量类型 变量名 = 初始化数值; 效果更好。
    • -这里的static其实是指类共享。静态变量本质是类共享变量;非静态变量是类不共享变量。

实例4------constexpr修饰构造函数/析构函数:

构造函数用constexpr修饰,要么非空要么只涉及基本四则运算和判断的简洁函数体。 析构函数用constexpr修饰,得到的效果是编译期对象销毁时没有运行期开销。 (constexpr修饰的效果要么是用于设定真常量,要么是能在编译期间能处理的事情给处理了。)

C++ 复制代码
class MyInt{

    public: 
        //构造函数
        constexpr MyInt (int val_) : val(val_) {}
        //析构函数
        constexpr ~MyInt() = default; //析构函数直接 = default 就行。
        //成员函数
        constexpr int get_val() const {
            return val;
        }

    private:
        int val;
};

int main() {
    //在编译期构造 MyInt 对象
    constexpr MyInt mi(100);
    constexpr int val = mi.get_val(); // 编译期求值为100
    return 0;
}

关联说明类成员函数的const尾缀修饰: constexpr int get_val() const { return val; //这个const成员函数只读取,没有修改val的权限。 }

const成员函数

作用是限定这个成员函数对成员变量的操作权限仅仅是只读。

  • 禁止修改类的非静态成员变量,确保这个函数只进行只读操作,不会改变对象的状态。
  • 禁止调用非const成员函数。
const 是 "承诺不修改成员变量",仅支持运行期执行;constexpr 是 "支持编译期求值",

实例5------constexpr修饰模板template:

使模板实例化后具备编译器求值能力。

C++ 复制代码
template <template T>
    constexpr T max_val(T a, T b){
        return a > b ? a : b;
    }
    
int main() {
    constexpr int max_num = max_val(5,10);
    //编译期求值: max_val(5,10)实例化得到int型数据,取值为10.
    return 0;
}
相关推荐
滑稽的小Z2 小时前
[PA 2017] Iloczyn 题解
c++·题解
_dindong2 小时前
笔试强训:Week -8
开发语言·c++·算法
云泽8082 小时前
C++ list容器模拟实现:迭代器、构造与STL风格编程
开发语言·c++·list
MSTcheng.2 小时前
【C++】set / multiset 保姆级教程:从底层原理到实战应用!
开发语言·c++·set
历程里程碑2 小时前
C++ 16:C++11新特化
c语言·开发语言·数据结构·c++·经验分享
xiaoye-duck2 小时前
吃透C++类和对象(中):拷贝构造函数的深度解析
c++
木心爱编程3 小时前
【Qt 5.14.2 新手实战】QTC++入门筑基——10 分钟做个文本编辑器:QLineEdit + QTextEdit 核心用法
java·c++·qt
肆悟先生3 小时前
3.15 引用类型
c++·算法
Cx330❀3 小时前
《C++ 动态规划》第001-002题:第N个泰波拉契数,三步问题
开发语言·c++·算法·动态规划