Consider the following example:
void f() requires true { }
int main() { f(); }
Clang(1) (DEMO) accepts this program, whereas GCC(1) (DEMO) rejects it with the following error:
error: constraints on a non-templated function
Note that the constraint expression can actually be used in Clang's case, as the following program is rejected by Clang:
void f() requires false { }
int main() { f(); } // // error: no matching function for call to 'f'
with Clang noting that that the declared f
is not a candidate as the constraints were not satisfied (for it to be a candidate for the f()
call; DEMO).
(1) GCC HEAD 11.0.0 20210124 and Clang HEAD 12.0.0 (20210124), -std=c++20
.
All standard references below refer, unless noted otherwise, to N4861 (March 2020 post-Prague working draft/C++20 DIS).
This is a Clang bug, and GCC is correct to reject the program, as per [dcl.decl]/4 (as well as [temp.constr.decl]/1) [emphasis mine]:
The optional requires-clause in an init-declarator or member-declarator shall be present only if the declarator declares a templated function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. [...]
The same paragraph also contains a (non-normative) example explicitly pointing out the OP's example as ill-formed:
[ Example:
void f1(int a) requires true; // error: non-templated function template<typename T> auto f2(T a) -> bool requires true; // OK // ...
— end example ]
We may note that in an earlier version of the (to become C++20) working draft, N4810, [dcl.decl]/4 had a weaker requirement for where requires-clauses were allowed to appear:
The optional requires-clause (Clause 13) in an init-declarator or member-declarator shall not be present when the declarator does not declare a function (9.2.3.5). [...]
[ Example:
void f1(int a) requires true; // OK // ...
— end example ]
where the non-normative example of the use case of the OP was explicitly shown as well-formed. The original intent there was arguably to allow constraining of non-template member functions of class templates based on the template parameters of the class template:
#include <iostream>
template<bool B>
struct S {
void f() requires B { std::cout << "true\n"; }
void f() requires (!B) { std::cout << "false\n"; }
};
int main() {
S<true>{}.f(); // true
S<false>{}.f(); // false
}
this is still allowed in the final state (intended for C++20) of [dcl.decl]/4 in N4861, where the restriction is to that of a templated function (see templated entity in [temp.pre]/8, particularly [temp.pre]/8.3), which does not only cover function templates (and function template members of non-templates and template class templates), but also non-template member functions of class templates.
Clang bug report:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With