Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ill-formed constraint expression

Regarding function f, is the substituted constraint expression of the non-type template argument of templated variable b a valid constant expression? Which specific wording of the C++20 standard either allows or forbids this?

struct s { static constexpr bool v = true; };
template<auto> inline constexpr bool b = true;
constexpr bool f(auto x) requires b<x.v> { return true; }
static_assert(f(s{})); // clang ok, gcc nope, msvc ok

Live example


The error message from GCC:

<source>:3:36: error: missing template arguments before '<' token
    3 | constexpr bool f(auto x) requires b<x.v> { return true; }
      |                                    ^
<source>:3:36: error: expected initializer before '<' token
<source>:4:15: error: 'f' was not declared in this scope
    4 | static_assert(f(s{}));
      |               ^
like image 430
303 Avatar asked Aug 12 '26 06:08

303


1 Answers

The reason this code is correct is that non of the wording in [expr.const]p5 applies:

An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

  • [...]

And none of the proceeding points apply. Since x.v does not apply an lvalue-to-rvalue conversion on x, and S::v is a constant expression which you can apply an lvalue-to-rvalue conversion on, x.v (when x is of type S and is not a reference) is a constant expression.


It looks like gcc is trying to parse b<x.v> as (b < x.v) > (as two relational operators), and so giving you an error. This is clearly a bug, as b< should be a template no matter what since b is a templated entity.

More examples of this gcc bug happening: https://godbolt.org/z/fP74hW1qs https://godbolt.org/z/19K4nYTjT

If you use the noexcept specifier instead of requires you get an interesting additional error message:

https://godbolt.org/z/8xqre5bbT (https://godbolt.org/z/cPYbb6vsq for trailing return type)

<source>:3:38: error: use of parameter outside function body before '.' token
    3 | constexpr bool f(auto x) noexcept(b<x.v>) { return true; }
      |                                      ^

Which makes me think at some point naming function parameters outside of the function body makes GCC error out but the warnings aren't well written when it's inside a requires.

like image 132
Artyer Avatar answered Aug 14 '26 12:08

Artyer