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

为何consteval函数内的模板可接受函数参数作为模板参数?

问题核心:consteval函数参数作为模板参数的两种情况差异

可正常编译的代码

#include <concepts>

enum class unit_type
{
};

template <typename Candidate>
concept unit_c = requires()
{
    requires std::semiregular<Candidate>;
    { Candidate::type } -> std::same_as<const unit_type&>;
};

struct unit
{
    static constexpr unit_type type{};
};

template<unit_c auto unit_1, unit_c auto unit_2>
struct unit_product
{
    static constexpr unit_type type{};
};

template <unit_c Unit1, unit_c Unit2>
consteval unit_c auto operator*(Unit1 unit_1, Unit2 unit_2) noexcept
{
    return unit_product<unit_1, unit_2>{};
}

int main()
{
    constexpr unit_c auto a = unit{} * unit{};

    return 0;
}

编译报错的代码

template <int val>
struct bla
{

};

consteval void bla_test(int val)
{
    bla<val>;
}

两者的核心差异在于参数是否属于编译期常量表达式,以及非类型模板参数的适配规则:

  1. 第一个案例:参数是满足unit_c概念的编译期常量对象

    • operator*的参数Unit1/Unit2是满足unit_c概念的类型,unit_c隐含了该类型支持常规构造复制,且调用时传入的unit{}是编译期常量表达式对象。
    • 模板unit_product的参数是unit_c auto类型的非类型模板参数,要求传入的对象必须是「类型符合unit_c的编译期常量」——这里的unit_1/unit_2本身就是编译期可知的常量对象,完全符合非类型模板参数的要求,因此可以直接传递。
  2. 第二个案例:参数是普通int,不属于编译期常量表达式

    • bla_test的参数val是普通int,哪怕bla_test是consteval函数(要求函数体在编译期执行),这个参数本身并不是常量表达式——它的取值是在函数调用时确定的(哪怕调用发生在编译期),但不具备「编译期常量」的固有属性,无法满足非类型模板参数必须是编译期确定值的要求。
    • 若要让这段代码编译通过,需要把参数改为编译期常量类型(比如std::integral_constant<int, N>),或是直接将参数设为模板参数,确保其值在编译期可知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 07:53:30