https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125372
Bug ID: 125372
Summary: [concepts] out-of-class definition rejected when
requires-clause names a static-constexpr-bool member
of the same class
Product: gcc
Version: 16.1.1
Status: UNCONFIRMED
Keywords: rejects-valid
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: pacoarjonilla at yahoo dot es
Target Milestone: ---
GCC rejects the out-of-class definition of a constrained member function
template when the requires-clause names a static-constexpr-bool member of
the enclosing class template. Every syntactic spelling of the constraint
expression -- unqualified `flag`, partially qualified `traits::flag`,
fully qualified `traits<T>::flag` -- is rejected with "no declaration
matches".
Related to PR 93638 (RESOLVED FIXED, 2020), which fixed the dependent-type
variant of this family; the fix did not extend to the static-constexpr-bool
member case reported here. PR 93638's own repro is accepted on gcc 15/16.
Minimal repro (no headers):
template< typename T >
struct traits
{
static constexpr bool flag = requires (T t) { t.f(); };
template< typename U > requires (flag) static void g(U &);
};
template< typename T >
template< typename U > requires (traits<T>::flag)
void traits<T>::g(U &) {}
struct S { void f(); };
int main() { S s; traits<S>::g(s); }
Command:
g++ -std=gnu++26 -c repro.c++
Also fails with -std=c++20 and -std=c++23.
Diagnostic (gcc 16.1.1):
repro.c++:16:1: error: no declaration matches 'void traits<T>::g(U&)'
[-Wtemplate-body]
16 | traits<T>:: g(U &) {}
| ^~~~~~~~~
candidate: 'template<class T> template<class U>
requires traits<T>::flag
static void traits<T>::g(U&)'
repro.c++:9:16:
9 | static void g(U &);
| ^
repro.c++:2:8: note: 'struct traits<T>' defined here
Note that gcc's own canonical printing of the in-class constraint is
"traits<T>::flag" -- the same spelling used in the out-of-class definition
-- yet the match still fails.
Versions tested:
gcc 16.1.1 20260508 (SUSE) -- rejects
gcc 15.2.1 20260202 (SUSE) -- rejects (same diagnostic, not a regression)
Workarounds (both accepted on gcc 15 and 16):
1. Move the bool to a sibling variable template:
template<typename T> constexpr bool flag_v =
requires (T t) { t.f(); };
template<typename T> struct traits {
template<typename U> requires (flag_v<T>) static void g(U &);
};
template<typename T>
template<typename U> requires (flag_v<T>)
void traits<T>::g(U &) {}
2. Define the constrained member inline inside the class body.
Spec reference: [temp.constr.decl]/2 -- "A constrained declaration may only
be redeclared using the same syntactic form." gcc's diagnostic prints a
canonical form that matches the out-of-class definition's spelling, yet
rejects it.
This bug report was assisted by Claude Code Opus 4.7 and reviewed by myself.