`consteval` 影响函数中表达式的分类/评估方式?

问题描述 投票:0回答:1

我有以下代码:

#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就没有错误。

虽然宏

__FILE__
是一个编译时常量,但似乎如果将其传递给
constexpr
函数,
s
将被视为非常量(即使它可以在编译时构造)但为什么呢?

但是如果

s
被认为是非常量表达式,我认为
return compile_time_trim(s);
甚至不会被评估。 但错误表明情况并非如此。 为什么?

谁能详细解释一下这是怎么回事?

谢谢!

c++ g++ c++23
1个回答
0
投票

这是一个已确认的 GCC 错误

return compile_time_trim(s);
不应在您的示例中执行。

GCC 是错误的,因为

if consteval
块在不应该执行的时候被执行了。 [stmt.if] p5 指出:

如果 consteval if 语句在“明显常量求值”的上下文中求值,则执行第一个子语句。

该术语定义如下:

表达式或转换是
明显常量评估

,如果它是:

a
    常量表达式
  • ,或 constexpr if 语句的条件 ([stmt.if]),或
  • 立即调用,或者
  • 将结果代入原子约束表达式以确定是否满足([temp.constr.atomic]),或者
  • 可在常量表达式中使用或具有常量初始化的变量的初始值设定项([basic.start.static])。
在语句
std::cout << best_effort_trim(__FILE__) << std::endl;

中,这些条件都不成立,因此不会进行持续评估。 该错误似乎与 GCC 在启用优化时错误地进行持续评估有关;该标准不允许这样任意的持续评估。

当您将 

best_effort_trim

更改为

consteval
时,该调用是立即调用,并且会按其应有的方式不断进行评估。
    

© www.soinside.com 2019 - 2024. All rights reserved.