You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20中如何让constexpr构造器对常量参数执行编译期检查

解决方案:C++20中为chrono强类型实现编译期溢出检查并兼容运行时输入

针对你遇到的问题——既要对delay_t{10s}这类常量字面量做编译期溢出检查,又要支持运行时传入的值——可以借助C++20的std::is_constant_evaluated()和constexpr构造函数实现两全的方案,核心思路是区分编译期与运行时求值场景,分别触发编译错误和运行时异常。

修改后的完整代码

#include <chrono>
#include <cstdint>
#include <stdexcept>
#include <type_traits>

// 自定义支持constexpr构造的异常类(C++20标准库异常暂不支持constexpr构造)
struct constexpr_delay_error : std::exception {
    const char* what() const noexcept override {
        return "delay cannot be represented within int32_t nanoseconds";
    }
};

struct delay_t {
    std::chrono::duration<int32_t, std::nano> value {};

    constexpr explicit delay_t(std::chrono::duration<int64_t, std::nano> delay) 
        : value(delay) 
    {
        using target_type = std::chrono::duration<int32_t, std::nano>;
        const auto delay_count = delay.count();

        // 检查是否超出目标类型的取值范围
        const bool out_of_range = 
            delay_count < target_type::min().count() || 
            delay_count > target_type::max().count();

        if (out_of_range) {
            if (std::is_constant_evaluated()) {
                // 编译期求值时抛出constexpr异常,触发编译错误
                throw constexpr_delay_error{};
            } else {
                // 运行时求值时抛出常规异常
                throw std::runtime_error("delay cannot be represented within int32_t nanoseconds");
            }
        }
    };
};

auto foo(delay_t delay) -> void {}

auto main() -> int {
    using namespace std::chrono_literals;

    foo(delay_t {10s});  // 现在会触发编译期错误
    // 运行时场景示例:
    // int64_t user_input = ...;
    // foo(delay_t {std::chrono::nanoseconds{user_input}}); // 运行时超出范围则抛异常

    return 0;
}

关键细节说明

  1. std::is_constant_evaluated():C++20引入的函数,用于判断当前代码是否处于常量表达式求值阶段(比如用字面量构造delay_t时)。
  2. constexpr异常类:由于C++20中标准库的std::runtime_error不支持constexpr构造,因此自定义一个可在constexpr上下文中抛出的异常类,编译期抛出该异常会直接触发编译错误。
  3. 范围检查逻辑:通过对比输入duration的计数值与目标类型(int32_t纳秒)的最小/最大值,判断是否存在溢出,比直接对比value != delay更直观准确。

替代方案:使用static_assert

如果偏好更直接的编译期断言,可以调整构造函数的检查逻辑,利用if constexpr确保仅在常量求值阶段触发static_assert:

constexpr explicit delay_t(std::chrono::duration<int64_t, std::nano> delay) 
    : value(delay) 
{
    using target_type = std::chrono::duration<int32_t, std::nano>;
    const auto delay_count = delay.count();

    if constexpr (std::is_constant_evaluated()) {
        static_assert(
            delay_count >= target_type::min().count() && delay_count <= target_type::max().count(),
            "delay cannot be represented within int32_t nanoseconds"
        );
    } else {
        if (delay_count < target_type::min().count() || delay_count > target_type::max().count()) {
            throw std::runtime_error("delay cannot be represented within int32_t nanoseconds");
        }
    }
}

这种方式会在编译期直接输出自定义的断言错误信息,可读性更强。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 22:55:39