niri 低功耗指南:让 Linux 笔记本多撑 4 小时的实用教程
2026/9/4 15:45:07
相关内容参考:C++中constexpr 与 explicit关键字使用详解
constexpr——“让编译器做更多事”在 C++11 之前:
const,但const 不保证编译期求值#define或enum——都不够安全、不支持函数、不支持复杂类型因此提出constexpr解决两个痛点:
例如:
constintN=foo(10);// 不能保证 foo(10) 在编译期运行intarr[N];// 可能无法作为数组大小C++ 希望:如果值能在编译期确定,就应该在编译期确定。
例如:
doublearea(doubler){return3.14159*r*r;}constexprdoubleA=area(10);// C++03 之前不行C++ 希望:
都能在编译期执行。
constexpr给 C++ 带来的核心能力极大提高运行效率 + 常量折叠 + 去掉运行时开销。
比#define可靠得多。
constexpr让模板元编程更直观,不必写复杂的 TMP 结构体推导。
例如:
structVec3{doublex,y,z;constexprVec3(doublex,doubley,doublez):x(x),y(y),z(z){}};让编译器“成为运行时”,能提前计算任何能计算的东西,提高性能与安全性,增强 C++ 的表达能力。
一句话:
explicit——“拒绝隐式转换导致的灾难”在 C++98 之前:
构造函数可以隐式调用,导致非常多的意外错误:
structVec{Vec(intx){}// 可隐式转换};Vec v=5;// ??? 编译器会自动调用 Vec(5)问题:
如:
booloperator==(constVec&,constVec&);Vec v;boolt=(v==10);// 会被隐式转成 Vec(10)这是非常危险的行为。
explicitVec(intx);禁止:
Vec v=5;// 不再允许保留:
Vecv(5);// 明确构造C++11 支持:
explicit用于转换运算符explicit(false)/explicit(true)(C++20)用于禁止 “过度智能” 的隐式行为。
explicitoperatorbool()const;防止:
Vector v;if(v){}//intx=v+1;// 防止自动转 bool 再转 int 的怪行为explicit 的目的就是阻止编译器做你没说过的隐式转换,避免隐式构造引发隐蔽 bug。
一句话:
| 关键字 | 核心动机 | 解决的问题 |
|---|---|---|
| constexpr | 让编译期可以计算更多东西,提高性能与安全性 | 编译期常量、constexpr 函数、constexpr 构造函数 |
| explicit | 禁止隐式转换,减少意料之外的 bug | 防止构造函数隐式调用,防止隐式转换 |
constvsconstexpr对比C++ 中const和constexpr都与常量相关,但用途和能力差异非常大:
| 特性 | const | constexpr |
|---|---|---|
| 定义 | 声明一个值不可修改 | 声明一个值或函数可以在编译期求值 |
| 是否保证编译期 | 不保证,可能运行时初始化 | 保证,如果满足条件,必须在编译期计算 |
| 适用对象 | 变量、成员、函数返回值 | 变量、成员、函数、构造函数、类常量 |
| 初始化 | 可以运行时初始化 | 必须用编译期常量初始化(C++14 起 relax,可有简单运行时计算) |
| 函数 | const函数限制成员修改(方法级) | constexpr函数在编译期求值,并且可用于常量表达式 |
| 数组长度 | const int N = 10; int arr[N];编译器可能支持,但不保证 | constexpr int N = 10; int arr[N];必定可用于编译期大小 |
| 优化 | 运行时常量,编译器可优化 | 编译期常量,可完全消除运行时开销 |
constinta=5;// 运行时可变对象也可初始化为常量intarr1[a];// 在一些编译器中可行,但非标准保证constexprintb=5;// 编译期常量intarr2[b];// 标准保证可用constintsquare_const(intx){returnx*x;}// 运行时求值constexprintsquare_constexpr(intx){returnx*x;}// 编译期求值可能square_constexpr(3)→ 编译期可求值square_const(3)→ 编译期不保证,只能运行时求值explicit在模板类 / 复杂构造中的用法explicit最初是为了防止隐式类型转换,但在模板类 / 泛型编程中尤其重要:
template<typenameT>structWrapper{explicitWrapper(T val):value(val){}T value;};Wrapper<int>w1(5);// 明确构造Wrapper<int>w2=5;// 错误,禁止隐式转换在模板类中,如果不加
explicit,可能会导致意想不到的隐式类型转换,尤其当模板参数为复杂类型(比如矩阵、点云类型)时。
template<typenameT>structPoint{explicitPoint(T x=0,T y=0,T z=0):x(x),y(y),z(z){}T x,y,z;};Point<int>p1(1,2,3);// 明确构造Point<int>p2;// 默认参数构造Point<int>p3={};// 禁止隐式列表初始化加
explicit可以避免模板类在列表初始化 / 隐式转换时产生不安全行为。
explicit与转换运算符(C++11+)C++11 引入了explicit operator,用于模板类中的类型安全转换:
template<typenameT>structVec{T x,y;explicitoperatorbool()const{returnx!=0||y!=0;}};Vec<int>v{0,0};if(v){}// 允许intn=v;// 禁止隐式转换explicit很容易产生隐式转换错误。const vs constexpr
const= 不可修改(可能运行时求值)constexpr= 编译期求值,可用于模板/数组/常量初始化explicit 在模板类中