约束表达式无效

303*_*303 8 c++ c++-concepts c++20

与 GCC 12.2 和 MSVC 19.33 相比,以下代码示例不能使用 Clang 15 或 Clang trunk 进行编译。嵌套required子句中的约束表达式是否无效?

struct t {
    constexpr auto b() const noexcept
    { return true; }
};

template<typename T>
concept c = requires(T t) {
    requires t.b();
};

static_assert(c<t>);
Run Code Online (Sandbox Code Playgroud)

Clang 产生的错误消息:

<source>:11:1: error: static assertion failed
static_assert(c<t>);
^             ~~~~
<source>:11:15: note: because 't' does not satisfy 'c'
static_assert(c<t>);
              ^
<source>:8:14: note: because 't.b()' would be invalid: constraint variable 't'
cannot be used in an evaluated context
    requires t.b();
             ^
Run Code Online (Sandbox Code Playgroud)

t.b()有趣的是,当将 的求值封装在 .gcc 文件中时,GCC 的错误也变得明显std::bool_constant。当改变约束表达式时:

template<typename T>
concept c = requires(T t) {
    requires std::bool_constant<t.b()>::value;
};
Run Code Online (Sandbox Code Playgroud)

GCC 实际上会产生以下错误,而 MSVC 仍然可以接受:

<source>:15:38: error: template argument 1 is invalid
   15 |     requires std::bool_constant<t.b()>::value;
Run Code Online (Sandbox Code Playgroud)

Sto*_*ica 8

\n

[expr.prim.req.general](强调我的)

\n

4要求表达式可以使用参数声明子句 ([dcl.fct]) 引入局部参数。要求表达式的本地参数不应有默认参数。本地参数引入的每个名称都在从其声明点到需求主体的右大括号的范围内。这些参数没有链接、存储或生命周期;它们仅用作定义需求的符号。[...]

\n
\n

您试图在表达式的(常量)求值中使用不存在的对象,它并不意味着工作。将复合要求表达式的参数视为简写declval。您可以在未评估的上下文中使用它们,检查类型等,但不能使用它们进行评估。

\n

明确地说

\n
\n

[expr.prim.req.nested]

\n

2局部参数只能作为约束表达式中未计算的操作数出现。\n[示例 2:

\n
template<typename T> concept C = requires (T a) {\n  requires sizeof(a) == 4;      // OK\n  requires a == 0;              // error: evaluation of a constraint > variable\n};\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x94 结束

\n
\n

所以 Clang 是这群编译器中唯一正确的编译器。

\n