跟我学C++中级篇——对类const关键字的分析说明

一、说明

前面多篇文章分析了常量的各种用法以及在新标准中的各种扩展。到目前为止,可以发现有几个长得差不多的关键字:从早期的const到C++11中的constexpr直到C++20中的consteval和constinit。这些长得类似的const有什么区别和联系呢?下面就对它们的具体应用进行分析和说明。

二、对比和分析

针对上面的这些长得差不多关键字,主要有以下的不同:

  1. const
    它是在C++中传统,const主要用来控制运行时对变量和表达式的只读性的控制。目的在于保护相关数据的安全性并进行接口的约束。其约束的变量可以根据时机在编译期或运行期进行求值
  2. constexpr
    C++11中引入的constexpr,用于在编译期的计算,也就是编译期求值,同时对变量和表达式的只读性控制。可以将运行期的计算转到编译期的计算和常量表达式的处理,当然,也支持运行期的处理
  3. consteval
    作为C++20引入的constexpr,主要用于立即函数处理,即它只能修饰函数,它修饰的函数及相关调用及相关求值都强制要求必须在编译期完成
  4. constinit
    constinit也是C++20引入的,它只能用于对静态或线程局部变量进行“常量初始化”(constant initialization)即编译期完成初始化。否则,会报编译错误。需要注意的是,它只能是初始化,完成后,这个变量是可以再次修改的即这个变量不是常量。

三、应用场景和限制分析

在了解上它们四个关键字的情况后,就可以根据其特点来确定其应用场景:

  1. 编译期计算
    需要在编译期计算的场景下,可以使用constexpr和consteval,这样,就可以把运行时的开销转移到编译期。另外在模板和元编程中这两个关键字也是经常使用的
  2. 接口约束和数据只读
    在与旧代码兼容以及需要接口的常量化控制,并且只是需要对数据常量化的处理时,可以考虑使用const。当然,很多情况下也可以使用constexpr
  3. 强制常量初始化
    在前面也提到过,在C++库中的全局(静态)变量调用时可能会产生初始化顺序的问题,从而产生意想不到的问题。而如果使用constinit则可以避免相关变量动态初始化,从而保证变量的依赖安全性。此外在全局配置处理、跨编译单元的变量以及线程局部存储等场景下都可以应用

虽然constinit无法限制变量的常量性,但它却也不允许联合使用const和constexpr来限制变量的常量性(只读性)。而const和constexpr则可以联合使用,不过是一种冗余的应用,没有什么实际意义。

四、例程

下面看一下具体的例程的对比:

//下面代码来自 cppreference
//constexpr
constexpr int f(); 
constexpr bool b1 = noexcept(f()); // false, undefined constexpr function
constexpr int f() { return 0; }
constexpr bool b2 = noexcept(f()); // true, f() is a constant expression
//consteval
consteval int sqr(int n)
{
    return n*n;
}
constexpr int r = sqr(100); // OK
 
int x = 100;
int r2 = sqr(x);            // Error: Call does not produce a constant
 
consteval int sqrsqr(int n)
{
    return sqr(sqr(n));     // Not a constant expression at this point, but OK
}
 
constexpr int dblsqr(int n)
{
    return 2 * sqr(n);      // Error: Enclosing function is not consteval
                            // and sqr(n) is not a constant
}
//constinit
const char* g() { return "dynamic initialization"; }
constexpr const char* f(bool p) { return p ? "constant initializer" : g(); }
 
constinit const char* c = f(true);     // OK
// constinit const char* d = f(false); // error

代码很简单,重点是对比一下。下面再看一个综合的应用:

#include <mutex>
#include <string>

int BASE_V = 0;
class Demo {
public:
  //  constexpr
  static constexpr double PI = 3.14;

  // consteval
  template <typename T> consteval static T ratioPI(T t) { return t * PI; }

  // constexpr-运行和编译期均可用
  template <typename T> constexpr static T less(T min, T max) { return min < max; }

  // const
  template <typename T> static const auto &get(const T &t) { return BASE_V > t ? BASE_V : 1; }
};

class ControlMsg {
public:
  void addmsg(const std::string &msg) {
    std::lock_guard lock(mutex_);
    msg_.append(msg);
  }

private:
  std::string msg_ = "";
  std::mutex mutex_;
};

// constinit
constinit ControlMsg msg;

// 使用示例
int main() {
  // 编译时
  constexpr double nPI = Demo::ratioPI(3.0);
  static_assert(nPI > Demo::PI && nPI < 5 * Demo::PI);

  // 运行时
  auto status = Demo::less(3, 5);

  //常量初始化
  msg.addmsg("Application started");

  return 0;
}

五、总结

有对比才有差距,才好掌握这四个关键字各自的特点和应用的场景。在实际应用的过程中,要根据实际情况来有针对性使用这些关键字。特别需要注意C++标准的版本不同的情况下,应用方式的不同。这样才能够编写出安全、高效的C++代码。

该文档【OpenCV实时视频拼接方案详解:基于特征匹配优化与自适应融合边界的无缝拼接设计】共计 597 页,共50个大章节,文档支持目录章节跳转同时还支持阅读器左侧书签大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿用作商业用途。文档前20个章节内容:【引言:实时视频拼接技术的现状与挑战、OpenCV视频拼接技术基础:从单帧到连续帧的处理逻辑、实时视频拼接系统的核心构成要素解析、视频帧采集与预处理:格式统一与畸变校正方案、基于OpenCV的摄像头标定参数获取全流程、基于人眼视觉特性的标准权重(通用场景首选)、高斯模糊在视频降噪中的参数优化与应用场景、特征点检测算法选型:SIFT、SURF与ORB的性能对比、ORB特征提取的原理与OpenCV实现细节、特征点描述子生成:二进制与浮点型描述子的优劣分析、暴力匹配与FLANN匹配算法的适用场景与性能测试、基于KD树的特征点快速匹配优化方案、匹配点对筛选:RANSAC算法的迭代次数与阈值设定、基础矩阵估计:从匹配点对到空间几何关系的推导、单应性矩阵计算:平面场景拼接的数学基础与实现、多视图几何约束在视频拼接中的应用、动态场景下特征点匹配的鲁棒性提升策略、基于光流法的特征点跟踪:减少重复检测的计算开销、特征点密度自适应调整:平衡拼接精度与实时性、图像配准精度评估指标与量化方法】。更多精品资源请访问 https://blog.csdn.net/ashyyyy/article/details/146464041
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值