require 子句中的表达式无效

303*_*303 6 c++ language-lawyer c++20

require 子句中的表达式是否b<[]{ return true; }()>符合 C++20 标准?由于某种原因,GCC 拒绝它并认为它是表达式错误,而 MSVC 和 Clang 接受它。

template<bool B>
inline constexpr bool b = B;
static_assert(requires { b<[]{ return true; }()>; });
Run Code Online (Sandbox Code Playgroud)

演示


GCC的错误信息:

<source>:3:15: error: static assertion failed
    3 | static_assert(requires { b<[]{ return true; }()>; });
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:3:15: note: constraints not satisfied
<source>:3:26: note: the required expression 'b<<expression error> >' is invalid,
because
    3 | static_assert(requires { b<[]{ return true; }()>; });
      |                          ^~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

And*_*dyG 6

这是一个已确认的 GCC错误。需要表达式是静态断言的有效表达式。语法的深度标准很疯狂,但我们开始了。

根据语法:

之后唯一的问题是(根据[decl.pre])您提供的 require 子句是否满足以下条件:

[表达式] E 根据上下文转换为 bool,转换后的表达式应为常量表达式

嗯,根据[exp.prim.req.general] , requires 表达式肯定可以转换为布尔值

要求表达式是 bool 类型的纯右值 [...]

您的需求表达式是一个简单的需求,只需要一个可能依赖或不依赖模板替换的表达式。在您的情况下,没有模板替换,因此传递所需的只是requires一个有效的表达式,任何有效的表达式。您的 lambda 非常有效(并且constexpr)。但请注意,返回的 lambdafalse应该同样有效并导致静态断言也通过

static_assert(requires { b<([](){ return false; }())>; }); // pass
Run Code Online (Sandbox Code Playgroud)

因此,使用 require 表达式而不进行模板替换可能不是一个好主意。


有趣的是, astatic_assert也可能有一个noexcept表达式,并且将 require 子句包装在一个表达式中会使GCC 13.2 通过

static_assert(noexcept(requires { b<([]{ return true; }())>; }));
Run Code Online (Sandbox Code Playgroud)