C++20中区分构造函数/函数是否以constexpr关键字实例化/调用并实现差异化逻辑的方法
C++20中区分构造函数/函数是否以constexpr关键字实例化/调用并实现差异化逻辑的方法
嘿,你这个需求其实在C++20里已经有非常直接的解决方案啦!就是利用标准库提供的std::is_constant_evaluated()函数,它能帮你精准判断当前代码是处于编译期常量求值上下文还是运行期执行上下文,完美实现你想要的差异化逻辑。
核心思路:std::is_constant_evaluated()的用法
这个函数是C++20新增的,它会返回一个bool值:
- 当代码正在编译期常量求值(比如
constexpr变量初始化、constexpr函数的编译期调用)时,返回true; - 当代码在运行期执行时,返回
false。
刚好能对应你想要区分的两种场景:用constexpr实例化时走编译期安全的逻辑,普通实例化时走运行期更高效的逻辑。
修改你的示例代码
我们把你给出的bytearray结构体改成符合需求的版本:
#include <iostream> #include <cstring> #include <type_traits> // 必须包含这个头文件才能用std::is_constant_evaluated template<size_t N> struct bytearray { char data[N]; constexpr bytearray(char val) : data() { if constexpr (std::is_constant_evaluated()) { // 编译期上下文:用循环初始化,因为std::memset不能在constexpr中使用 for (size_t i = 0; i < N; ++i) { data[i] = val; } } else { // 运行期上下文:用std::memset,更高效 std::memset(data, val, N); } } }; int main() { // 编译期初始化:走for循环分支 constexpr bytearray<10> A(7); // 运行期初始化:走std::memset分支 bytearray<10> B(7); // 验证一下结果(可选) for (size_t i = 0; i < 10; ++i) { std::cout << static_cast<int>(A.data[i]) << " "; } std::cout << "\n"; for (size_t i = 0; i < 10; ++i) { std::cout << static_cast<int>(B.data[i]) << " "; } }
这段代码完全符合你的预期:constexpr实例化的A会在编译期用循环填充数组,而普通实例化的B会在运行期用memset完成初始化。
扩展到其他函数/方法
这个逻辑同样可以推广到其他constexpr函数或成员函数上。比如我们给bytearray加一个求和的成员函数,编译期用constexpr循环,运行期用更高效的运行期算法:
constexpr int sum() const { if constexpr (std::is_constant_evaluated()) { int total = 0; for (size_t i = 0; i < N; ++i) { total += data[i]; } return total; } else { // 运行期可以用更灵活的实现,这里用简单循环演示差异化 int total = 0; for (const auto& c : data) { total += c; } return total; } }
这样,当你在编译期调用A.sum()时会走第一个分支,运行期调用B.sum()时走第二个分支。
注意事项
- 必须包含
<type_traits>头文件:std::is_constant_evaluated()定义在这个头文件里,别忘了引入。 - 确保分支代码的合法性:编译期分支里不能出现非constexpr的操作(比如
std::memset就不能在constexpr上下文里用),否则会触发编译错误。 - 不要依赖函数是否被声明为constexpr:即使函数是
constexpr的,只要它在运行期被调用,std::is_constant_evaluated()就会返回false,这正是我们需要的行为。
备注:内容来源于stack exchange,提问作者0xdeadbeef
相关产品推荐
相关产品推荐

