C++23新特性_if consteval

文章目录

  • [第一章 C++23语言特性](#第一章 C++23语言特性)
    • [1.2 if consteval](#1.2 if consteval)
      • [1.2.1 语法格式](#1.2.1 语法格式)
      • [1.2.2 举例说明](#1.2.2 举例说明)
      • [1.2.3 总结](#1.2.3 总结)

本文讲解C++23新特性之if consteval.

第一章 C++23语言特性

1.2 if consteval

在 C++20 中,我们使用 std::is_constant_evaluated() 来判断当前是否在编译期执行。虽然它能工作,但存在两个显著的陷阱:

缺陷:与if constexpr混用

cpp 复制代码
// 错误示范!
if constexpr (std::is_constant_evaluated()) { 
    // ... 
}

这是错误的,因为 std::is_constant_evaluated() 在 if constexpr 的条件中永远返回 true(因为 if constexpr 强制进行常量折叠)。这导致运行时分支永远被丢弃。

正确写法是使用普通的 if:

cpp 复制代码
    constexpr double power(double base, int exp)
    {
        // 检查当前调用是否在编译期常量上下文中
        if (std::is_constant_evaluated())
        {
            // 编译期路径:使用简单的循环
            // 这个实现对编译器友好
            double res = 1.0;
            for (int i = 0; i < exp; ++i) {
                res *= base;
            }
            return res;
        }
        else
        {
            // 运行时路径:调用标准库中更高效的函数
            // std::pow 不是 constexpr,所以不能在编译期路径中使用
            return std::pow(base, exp);
        }
    }
    void test()
    {
        // 1 编译期求值
		// 一个constexpr ,所以会在编译期计算
		constexpr double compiled_result = power(2.0, 10);
		cout << "Compiled Result: " << compiled_result << endl;
		static_assert(compiled_result == 1024.0,"非编译期间计算");

        // 2 运行时求值
        double runtime_base = 2.0;
        int runtime_exp = 10;
        double runtime_result = power(runtime_base, runtime_exp);
		cout << "Runtime Result: " << runtime_result << endl;
    }

为了解决这个问题,C++23引入了if consteval,直接替代库函数std::is_constant_evaluated()。

1.2.1 语法格式

语法非常简洁,直接作为 if 语句的一种特殊形式。

cpp 复制代码
if consteval {
    // 这个块中的代码仅在"常量求值上下文"中执行
    // 编译器保证这里不会生成运行时代码
} else {
    // 这个块中的代码仅在"运行时"执行
}

1.2.2 举例说明

示例1:编译期生成表 vs 运行时查表

编译期:我们希望直接计算出结果,或者生成一个查找表。

运行时:我们希望直接查表,或者调用硬件加速指令,而不是重新计算。

cpp 复制代码
    // 假设这是一个复杂的算法, 在编译时期计算
    constexpr double heavy_calc(double x)
    {
        double res = x;
        // 使用一个可在编译期执行的循环来模拟耗时操作
        for (int i = 0; i < 100; ++i)
        {
            res = res / 1.01 + x / (i + 1); 
        }
        return res;
    }

    // 
    constexpr double smart_calc(double x)
    {
        if consteval  // 编译期间
        {
            // 编译期:我们不在乎耗时,直接暴力算出一个精确值
            // 这样生成的二进制里直接就是一个 double 常量
            return heavy_calc(x);
        }
        else 
        {
            // 运行时:heavy_calc 太慢了,我们用一个近似公式或查表
            // 或者调用 SIMD 优化的版本
            return x * 1.5; // 模拟快速近似
        }
    }

    void test() 
    {
        // 场景 A: 编译期计算
        // 编译器会进入 if consteval 分支,直接把 result_const 编译成常量
        constexpr double result_const = smart_calc(2.0);

        // 场景 B: 运行时计算
        double input = 2.0;
        // 编译器会生成调用 else 分支的代码
        double result_runtime = smart_calc(input);

        std::cout << result_const << " vs " << result_runtime << std::endl;
    }
示例2:字符串hash

这是游戏引擎和高频交易系统中常见的优化。

编译期:字符串字面量(如 "PlayerHealth")应该在编译期直接被哈希成一个整数 ID。

运行时:动态生成的字符串(如用户输入)需要在运行时计算哈希。

cpp 复制代码
    // 一个简单的编译期间字符串哈希函数
    constexpr size_t const_hash(string_view s)
    {
        size_t hash = 5381;
        for (char c : s)
        {
            hash = ((hash << 5) + hash) + static_cast<size_t>(c); // hash * 33 + c
        }
		return hash;
    }

	// 一个超快运行的hash算法,假如使用了AVX2指令集等硬件加速
    size_t runtime_hash(std::string_view s)
    {
		// 这里简单使用标准库的哈希作为示例
        return std::hash<std::string_view>{}(s);
	}

    constexpr size_t get_hash(std::string_view s) 
    {
        if consteval
        {
            // 编译期:使用普通 C++ 代码实现的哈希
            return const_hash(s);
        }
        else // 运行时:使用硬件加速的哈希
        {
            return runtime_hash(s);
        }
    }

    void test()
    {
        // 编译期计算
        constexpr size_t hash1 = get_hash("Hello, World!");
        std::cout << "Compile-time hash: " << hash1 << std::endl;

        // 运行时计算
        std::string input = "Hello, World!";
        size_t hash2 = get_hash(input);
        std::cout << "Runtime hash: " << hash2 << std::endl;
	}
示例3:format实现原理

C++20中的format在编译期间会检查字符串是否合法,可以使用if consteval 实现这种机制,在if consteval块中编写复杂的静态断言逻辑,在运行时块中仅执行高效的字符串拷贝。

1.2.3 总结

if consteval 修复了std::is_constant_evaluated 容易被误用于 if constexpr 的陷阱,使用起来也更简洁。

代码一目了然:如果是编译期间走一条路,运行期间走一条路。

建议在C++23下,分编译期和运行期的场景,使用if consteval 替换 std::is_constant_evaluated().

相关推荐
落羽的落羽1 小时前
【Linux系统】初探 虚拟地址空间
linux·运维·服务器·c++·人工智能·学习·机器学习
Drone_xjw1 小时前
【CPP回调函数】以无人机系统为例梳理回调函数使用
c++·无人机
liu****1 小时前
11.字符函数和字符串函数(二)
c语言·开发语言·数据结构·c++·算法
Tandy12356_1 小时前
手写TCP/IP协议栈——以太网数据包处理
网络·c++·网络协议·tcp/ip
郝学胜-神的一滴1 小时前
Linux中的alarm函数详解:定时器信号处理指南
linux·服务器·开发语言·c++·程序人生
郝学胜-神的一滴1 小时前
Linux kill命令与kill函数:从信号原理到实战解析
linux·服务器·开发语言·c++·程序人生
起个名字费劲死了1 小时前
基于Mingw64 tesseract 实现英文字符和数字识别
c++·qt·字符识别
曼巴UE51 小时前
UE5 C++ 动态单播放
c++·ue5
陌路201 小时前
C++ 单例模式
开发语言·c++