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

consteval对函数表达式分类/求值的影响及代码报错解析

问题解析:constexpr函数中if consteval分支的编译错误

相关代码

#include <string_view>
#include <iostream>
#include <cstring>

consteval const char* compile_time_trim(const std::string_view& s) noexcept{
    return s.data() + s.find("/app/") + strlen("/app/");
}

constexpr const char* best_effort_trim(const std::string_view& s) noexcept{
    if consteval {
        return compile_time_trim(s);
    }
    else {
        return s.data();
    }
}

int main() {
    std::cout << best_effort_trim(__FILE__) << std::endl;
}

GCC 14.1编译错误信息

<source>: In function 'int main()':
<source>:19:34:   in 'constexpr' expansion of 'best_effort_trim(std::basic_string_view<char>(((const char*)"<source>")))'
<source>:11:33: error: call to consteval function 'compile_time_trim((* & s))' is not a constant expression
   11 |         return compile_time_trim(s);
      |                ~~~~~~~~~~~~~~~~~^~~
In file included from <source>:1:
<source>:19:34:   in 'constexpr' expansion of 'best_effort_trim(std::basic_string_view<char>(((const char*)"<source>")))'
<source>:11:33:   in 'constexpr' expansion of 'compile_time_trim((* & s))'
<source>:6:18:   in 'constexpr' expansion of '(& s)->std::basic_string_view<char>::data()'
/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/string_view:290:22: error: '*(const std::basic_string_view<char>*)this' is not a constant expression
  290 |       { return this->_M_str; }
      |                ~~~~~~^~~~~~
Compiler returned: 1

现象说明

将constexpr const char* best_effort_trim(改为consteval const char* best_effort_trim(后,GCC编译无错误。

核心疑问

  1. 宏__FILE__是编译时常量,传入constexpr函数后,参数s为何被视为非常量?
  2. 若s是非常量表达式,为何return compile_time_trim(s);分支仍会被求值并触发错误?

解答

1. constexpr函数参数为何不被视为常量表达式?

C++标准规定:constexpr函数的参数本身不属于常量表达式,哪怕传入的实参是编译期常量。这是因为constexpr函数需要兼容两种执行场景:编译期求值和运行时求值。

当调用best_effort_trim(__FILE__)时,__FILE__确实是编译期字符串,但s作为函数形参,是局部std::string_view对象的引用。在constexpr函数的编译期求值语境中,形参的值类别为非常量——你无法用它初始化constexpr变量,也不能传递给要求常量表达式的consteval函数。

而将best_effort_trim改为consteval函数后,函数只能在编译期执行,编译器会把实参的常量属性直接传递给形参,此时s会被当作常量表达式处理,因此compile_time_trim(s)能正常调用。

2. 非常量情况下为何consteval分支仍被求值?

if consteval是C++20的编译期分支判断,它的分支选择由调用语境决定:如果当前是编译期求值语境,就走consteval分支;如果是运行时求值语境,就走else分支。

在main中调用constexpr函数best_effort_trim时,因为实参是编译常量,编译器会尝试进行编译期求值,此时if consteval条件为真,进入return compile_time_trim(s);分支。但如前所述,constexpr函数的形参s不是常量表达式,而compile_time_trim是consteval函数,要求参数必须是常量表达式,因此触发错误。

如果传入的是运行时字符串(比如用户输入的字符串),编译器无法进行编译期求值,就会走else分支,不会调用consteval函数,也就不会报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:45:22