自学内容网 自学内容网

C++ constexpr

定义

  1. C++11新增语法
  2. 编译器常量,在编译器求值
  3. constexpr函数或变量必须满足一定条件才能在编译期求值。constexpr只能进行简单操作(算术运算、逻辑运算),不能包含运行时才能确定的操作,如内存分配、文件读取

const对比

以前的const修饰符并不能保证产生编译期常量,因此某些用法,比如用const常量声明数组长度不能保证可行。相比之下,constexpr类型具有更强的编译期检查,可以在编译阶段就发现常量能否在编译阶段确定

example

  1. 无法初始化std::vectorstd::list
    1. std::vector为例,它在内部管理着一块动态分配的连续内存区域来存储元素。在创建std::vector对象时,它会根据需要分配内存,这个过程涉及到运行时的内存分配操作,无法在编译期完成
    2. 例如,constexpr std::vector<int> v = {1, 2, 3};会报错。因为std::vector的构造函数需要在运行时确定内存分配的大小和位置,即使提供了初始化列表,也无法在编译期确定这些内存相关的操作。
    3. 代替方案:可以考虑使用std::arraystd::array是一个固定大小的数组容器,它的大小在编译期是确定的,可以用于替代std::vector在编译期常量场景下的部分功能。例如,constexpr std::array<int, 3> a = {1, 2, 3};是合法的
  2. 无法初始化std::stringQString
    1. std::string是一个类类型,它的构造涉及到动态内存分配(用于存储字符串内容)等运行时操作。例如,当创建一个std::string对象时,它会在堆上分配内存来存储字符序列,这个过程是在运行时发生的,无法在编译期完成
    2. C++标准库在设计时没有为 std::string 提供 constexpr 构造函数。在 C++20 之前,标准库中的大部分容器类都不能使用 constexpr 构造函数
    3. 代替方案:可以使用const char*const char[],形如constexpr std::string str = "hello";
    4. 代替方案std::string_view(C++17)是一个轻量级的字符串视图类,它不拥有字符串的内容,只是提供了对字符串内容的查看功能。在某些情况下,可以将std::string_view作为编译期常量来处理字符串
      1. 不过需要注意的是,std::string_view本身只是一个视图,如果要将其转换为std::string,仍然可能涉及到运行时操作,如复制字符串内容到新的std::string对象中。但在只需要查看字符串内容而不涉及修改和存储的场景下,std::string_view可以作为一种编译期常量来使用
  3. 无法初始化输入/输出(I/O)操作的类型(如std::ofstreamstd::ifstream等)
    1. std::ofstream(用于输出文件流)和std::ifstream(用于输入文件流)这样的类型,它们的操作本质上依赖于外部设备(如硬盘上的文件)和运行时的系统调用。例如,当打开一个文件流时,需要在运行时查找文件系统中的文件、获取文件句柄等操作,这些操作无法在编译期完成。如constexpr std::ofstream out("output.txt");是非法的,因为在编译期无法执行打开文件并建立输出流的操作。
    2. 替代方案:如果只是需要在编译期确定一些文件相关的常量信息,比如文件名,可以使用constexpr const char*来表示文件名。例如,constexpr const char* filename = "output.txt";,然后在运行时使用这个常量来打开文件流,如std::ofstream out(filename);
  4. 无法初始化大多数自定义类(如果其构造函数涉及非constexpr操作)
    1. 对于自定义类,如果其构造函数包含运行时操作,如动态内存分配、调用非constexpr函数、等待用户输入等,那么这个类就不能在编译期初始化。例如,假设有一个自定义类MyClass,其构造函数如下:
      class MyClass {
      public:
         MyClass() {
             // 动态分配内存
             data = new int;
         }
      private:
         int* data;
      };
      
      对于这样的类,constexpr MyClass obj;是不合法的,因为其构造函数中的动态内存分配操作无法在编译期完成
    2. 替代方案:要使自定义类能够在编译期初始化,需要确保其构造函数中的操作都是可以在编译期完成的。需要修改构造函数,避免动态内存分配等运行时操作。例如,可以将上述MyClass的构造函数修改为使用静态存储的成员变量,或者使用constexpr函数来初始化成员变量等方式,使其符合编译期初始化的要求

原文地址:https://blog.csdn.net/weixin_44623642/article/details/143820995

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!