C++23 对部分特性的 constexpr 支持

文章目录

    • [1. `std::bitset (P2417R2)`](#1. std::bitset (P2417R2))
      • [1.1 概述](#1.1 概述)
      • [1.2 具体变化](#1.2 具体变化)
      • [1.3 优势](#1.3 优势)
    • [2. `std::unique_ptr (P2273R3)`](#2. std::unique_ptr (P2273R3))
      • [2.1 概述](#2.1 概述)
      • [2.2 具体变化](#2.2 具体变化)
      • [2.3 优势](#2.3 优势)
    • [3. `std::type_info::operator== (P1328R1)`](#3. std::type_info::operator== (P1328R1))
      • [3.1 概述](#3.1 概述)
      • [3.2 具体变化](#3.2 具体变化)
      • [3.3 优势](#3.3 优势)
    • [4. 一些 `<cmath>` 函数 (P0533R9)](#4. 一些 <cmath> 函数 (P0533R9))
      • [4.1 概述](#4.1 概述)
      • [4.2 具体变化](#4.2 具体变化)
      • [4.3 优势](#4.3 优势)
    • [5. `std::to_chars` 和 `std::from_chars` 的整型重载 (P2291R3)](#5. std::to_charsstd::from_chars 的整型重载 (P2291R3))
      • [5.1 概述](#5.1 概述)
      • [5.2 具体变化](#5.2 具体变化)
      • [5.3 优势](#5.3 优势)

在 C++ 编程中, constexpr 关键字自 C++11 引入以来,便致力于让更多的计算在编译时完成,以此提升程序的性能与效率。C++23 进一步拓展了 constexpr 的应用范畴,为 std::bitsetstd::unique_ptrstd::type_info::operator==、部分 <cmath> 函数以及 std::to_charsstd::from_chars 的整型重载等带来了 constexpr 支持。下面将详细介绍这些特性在 C++23 中的 constexpr 支持情况。

1. std::bitset (P2417R2)

1.1 概述

std::bitset 是一个固定大小的位序列容器,在 C++23 之前,仅有一个构造函数和 operator[] 被标记为 constexpr。P2417R2 提案对 std::bitsetconstexpr 接口进行了扩展,鉴于 std::string 能够是 constexprstd::bitset 的所有内部结构以及完整的 API 如今都能够是 constexpr

1.2 具体变化

在 C++23 里,std::bitset 的更多构造函数和成员函数被标记为 constexpr。例如:

cpp 复制代码
#include <bitset>
#include <iostream>

int main() {
    constexpr short i = 15;
    constexpr int numberOfBitsInInt = sizeof(i) * 8;
    // 使用 constexpr 构造 std::bitset
    constexpr std::bitset<numberOfBitsInInt> bits(i); 
    std::cout << "i:" << i << ", i as binary: " << bits << '\n'; 
    return 0;
}

在上述代码中,std::bitset 的构造函数被标记为 constexpr,从而能够在编译时构建 bitset 对象。

1.3 优势

这一改进让开发者能够在编译时对 bitset 进行操作和计算,减少运行时的开销。例如,在编译时就能确定位序列的值,进而避免在运行时进行额外的计算。

2. std::unique_ptr (P2273R3)

2.1 概述

std::unique_ptr 是一种智能指针,用于管理动态分配的对象,保证对象的所有权唯一。P2273R3 提案被接纳后,std::unique_ptr 在 C++23 中支持 constexpr

2.2 具体变化

多个构造函数、析构函数、赋值运算符等都被标记为 constexpr。例如:

cpp 复制代码
#include <memory>

struct Car {
    virtual ~Car() = default;
    constexpr virtual int speed() const = 0;
};

struct Mercedes : Car {
    constexpr int speed() const override { return 5; }
}; 

struct Toyota : Car {
    constexpr int speed() const override { return 6; }
}; 

struct Tesla : Car {
    constexpr int speed() const override { return 9; }
}; 

constexpr Car* CreateCar(int i) {
    switch(i) {
        case 0: return new Mercedes{};
        case 1: return new Toyota{};
        case 2: return new Tesla{};
    }
    return nullptr; 
}

constexpr int FastestCar() {
    int max = -1;
    int maxId = -1;
    for(int i = 0; i < 3; ++i) {
        const auto* car = CreateCar(i);
        if(car->speed() > max) {
            max = car->speed();
            maxId = i;
        }
        delete car;
    }
    return maxId; 
}

void Use() {
    static_assert(FastestCar() == 2); 
}

在这个示例中,CreateCarFastestCar 函数能够在编译时运行,并且 std::unique_ptr 的相关操作也能够在编译时完成。

2.3 优势

这使得 std::unique_ptr 可以在编译时进行实例化和操作,有助于在编译时进行更多的检查和优化,减少运行时的错误。

3. std::type_info::operator== (P1328R1)

3.1 概述

std::type_info 用于在运行时获取类型信息,而 std::type_info::operator== 用于比较两个类型信息对象是否指代相同的类型。在 C++23 之前,typeid 虽允许在常量表达式中使用,但得到的 std::type_info 对象因没有 constexpr 成员函数而无法使用。P1328R1 提案建议将 std::type_info::operator== 标记为 constexpr

3.2 具体变化

在 C++23 中,std::type_info::operator== 被正式标记为 constexpr。例如:

cpp 复制代码
#include <iostream>
#include <typeinfo>

class Base { virtual void foo() {} };
class Derived : public Base {};

int main() {
    constexpr bool sameType = (typeid(Base) == typeid(Base));
    std::cout << "Same type: " << (sameType ? "Yes" : "No") << std::endl;
    return 0;
}

在上述代码中,typeidoperator== 的比较操作能够在编译时完成。

3.3 优势

这使得在常量表达式中使用 typeid 更具实用性,能够在编译时进行类型比较,提前发现类型不匹配的问题。

4. 一些 <cmath> 函数 (P0533R9)

4.1 概述

<cmath> 头文件包含了众多数学函数。有提案被接受作为 C++23 的一部分,该提案使大量 <cmath> 函数支持 constexpr,不过在 clang/llvm 中尚未实现。

4.2 具体变化

std::fmax 为例,可通过以下策略使其支持 constexpr

cpp 复制代码
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_CXX23 float fmax(float __x, float __y) _NOEXCEPT {
  if consteval { 
    return __builtin_fmax(__x, __y); 
  } else {
    return ::fmaxf(__x, __y); 
  }
}

在编译时,如果是常量求值,就使用 constexpr 内置函数;否则,使用实际的实现。

4.3 优势

让数学函数能够在编译时进行计算,减少运行时的计算开销,提高程序的性能。

5. std::to_charsstd::from_chars 的整型重载 (P2291R3)

5.1 概述

std::to_charsstd::from_chars 是 C++17 引入的用于字符序列和数值之间转换的函数。P2291R3 提案使它们的整型重载支持 constexpr

5.2 具体变化

在 C++23 中,这些整型重载函数可以在编译时进行转换操作。例如:

cpp 复制代码
#include <charconv>
#include <iostream>

int main() {
    char buffer[10];
    constexpr int value = 42;
    auto result = std::to_chars(buffer, buffer + sizeof(buffer), value);
    if (result.ec == std::errc()) {
        std::cout << "Converted value: " << std::string(buffer, result.ptr) << std::endl;
    }
    return 0;
}

在上述代码中,std::to_chars 的整型重载可以在编译时将整数转换为字符序列。

5.3 优势

在编译时进行字符和数值的转换,能够避免运行时的开销,并且可以在编译时检查转换是否成功,提高程序的安全性。

综上所述,C++23 对这些特性的 constexpr 支持进一步增强了编译时计算的能力,减少了运行时的开销,提高了程序的性能和安全性。开发者可以更充分地利用编译时的计算资源,编写更高效、更安全的代码。

相关推荐
蒟蒻小袁13 分钟前
力扣面试150题--二叉树的层平均值
算法·leetcode·面试
geneculture23 分钟前
技术-工程-管用养修保-智能硬件-智能软件五维黄金序位模型
大数据·人工智能·算法·数学建模·智能硬件·工程技术·融智学的重要应用
1001101_QIA26 分钟前
【QT】理解QT机制之“元对象系统”
开发语言·c++·qt·算法
a东方青34 分钟前
[蓝桥杯C++ 2024 国 B ] 立定跳远(二分)
c++·算法·蓝桥杯·c++20
Studying 开龙wu1 小时前
机器学习无监督学习sklearn实战一:K-Means 算法聚类对葡萄酒数据集进行聚类分析和可视化( 主成分分析PCA特征降维)
算法·机器学习·sklearn
似水এ᭄往昔1 小时前
【数据结构】--二叉树--堆(上)
数据结构·算法
心软且酷丶1 小时前
leetcode:479. 最大回文数乘积(python3解法,数学相关算法题)
python·算法·leetcode
里欧布鲁斯2 小时前
Sums of Sliding Window Maximum_abc407F分析与解答
算法
倔强的石头_2 小时前
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
后端·算法
QZQ541882 小时前
MIT6.824(2024春)Raft-lab3B代码分析
算法