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.
  • [Bug c++/125372] New: [concepts... pacoarjonilla at yahoo dot es via Gcc-bugs

Reply via email to