问题
When the member of a class template that uses the requires
clause is defined outside the class, gcc
does not complain if requires
is not specified, whereas clang
does.
Consider the code snippet below:
#include <concepts>
template<typename Container>
requires std::integral<typename Container::value_type>
class Foo {
public:
void func();
};
template<typename Container>
void Foo<Container>::func()
{}
The compilation using gcc
does not complain.
While clang
reports the following error:
❯ clang++ -std=c++2a test.cpp
test.cpp:10:1: error: requires clause differs in template redeclaration
template<typename Container>
^
test.cpp:4:19: note: previous template declaration is here
requires std::integral<typename Container::value_type>
^
1 error generated.
If I change the definition as below:
template<typename Container>
requires std::integral<typename Container::value_type>
void Foo<Container>::func()
{}
now clang
does not complain.
Output from gcc --version
:
gcc (GCC) 10.2.0
Output from clang --version
:
clang version 10.0.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Is this a bug to be reported?
回答1:
A bug should be filed for GCC, because it accepts the code, even though the declaration of the member outside the class does not have an equivalent template-head.
[temp.class]
3 When a member function, a member class, a member enumeration, a static data member or a member template of a class template is defined outside of the class template definition, the member definition is defined as a template definition in which the template-head is equivalent to that of the class template ([temp.over.link]).
[temp.over.link]
6 Two template-heads are equivalent if their template-parameter-lists have the same length, corresponding template-parameters are equivalent and are both declared with type-constraints that are equivalent if either template-parameter is declared with a type-constraint, and if either template-head has a requires-clause, they both have requires-clauses and the corresponding constraint-expressions are equivalent.
The equivalence of templates-heads requires that both have an equivalent requires clause. Omitting it entirely breaks the equivalence.
回答2:
From [temp.mem.func]/1 [extract, emphasis mine]:
A member function of a class template may be defined outside of the class template definition in which it is declared. [Example:
A constrained member function can be defined out of line:
template<typename T> concept C = requires { typename T::type; }; template<typename T> struct S { void f() requires C<T>; void g() requires C<T>; }; template<typename T> void S<T>::f() requires C<T> { } // OK template<typename T> void S<T>::g() { } // error: no matching function in S<T>
— end example]
taking note particularly the final example of the (non-normative) text.
Thus, Clang is correct to reject whereas GCC is wrong to accept the first program as the out-of-line definition
template<typename Container> void Foo<Container>::func() {}
does not match any function in Foo<Container>
.
(I have not yet found an open GCC bug report for this)
来源:https://stackoverflow.com/questions/63628752/does-a-class-templates-requires-clause-have-to-be-repeated-outside-member-defin