C++23 对部分特性的 constexpr 支持
文章目录
- 1. `std::bitset (P2417R2)`
- 1.1 概述
- 1.2 具体变化
- 1.3 优势
- 2. `std::unique_ptr (P2273R3)`
- 2.1 概述
- 2.2 具体变化
- 2.3 优势
- 3. `std::type_info::operator== (P1328R1)`
- 3.1 概述
- 3.2 具体变化
- 3.3 优势
- 4. 一些 `<cmath>` 函数 (P0533R9)
- 4.1 概述
- 4.2 具体变化
- 4.3 优势
- 5. `std::to_chars` 和 `std::from_chars` 的整型重载 (P2291R3)
- 5.1 概述
- 5.2 具体变化
- 5.3 优势
在 C++ 编程中,
constexpr
关键字自 C++11 引入以来,便致力于让更多的计算在编译时完成,以此提升程序的性能与效率。C++23 进一步拓展了
constexpr
的应用范畴,为
std::bitset
、
std::unique_ptr
、
std::type_info::operator==
、部分
<cmath>
函数以及
std::to_chars
和
std::from_chars
的整型重载等带来了
constexpr
支持。下面将详细介绍这些特性在 C++23 中的
constexpr
支持情况。
1. std::bitset (P2417R2)
1.1 概述
std::bitset
是一个固定大小的位序列容器,在 C++23 之前,仅有一个构造函数和 operator[]
被标记为 constexpr
。P2417R2 提案对 std::bitset
的 constexpr
接口进行了扩展,鉴于 std::string
能够是 constexpr
,std::bitset
的所有内部结构以及完整的 API 如今都能够是 constexpr
。
1.2 具体变化
在 C++23 里,std::bitset
的更多构造函数和成员函数被标记为 constexpr
。例如:
#include <bitset>
#include <iostream>int main() {constexpr short i = 15;constexpr int numberOfBitsInInt = sizeof(i) * 8;// 使用 constexpr 构造 std::bitsetconstexpr 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
。例如:
#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);
}
在这个示例中,CreateCar
和 FastestCar
函数能够在编译时运行,并且 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
。例如:
#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;
}
在上述代码中,typeid
和 operator==
的比较操作能够在编译时完成。
3.3 优势
这使得在常量表达式中使用 typeid
更具实用性,能够在编译时进行类型比较,提前发现类型不匹配的问题。
4. 一些 <cmath>
函数 (P0533R9)
4.1 概述
<cmath>
头文件包含了众多数学函数。有提案被接受作为 C++23 的一部分,该提案使大量 <cmath>
函数支持 constexpr
,不过在 clang/llvm 中尚未实现。
4.2 具体变化
以 std::fmax
为例,可通过以下策略使其支持 constexpr
:
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_chars
和 std::from_chars
的整型重载 (P2291R3)
5.1 概述
std::to_chars
和 std::from_chars
是 C++17 引入的用于字符序列和数值之间转换的函数。P2291R3 提案使它们的整型重载支持 constexpr
。
5.2 具体变化
在 C++23 中,这些整型重载函数可以在编译时进行转换操作。例如:
#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
支持进一步增强了编译时计算的能力,减少了运行时的开销,提高了程序的性能和安全性。开发者可以更充分地利用编译时的计算资源,编写更高效、更安全的代码。