g++ happily accepts the following code, whereas clang nor msvc are able to match out of line definitions.
Any idea why ?
template <bool B>
struct test
{
test() requires (B);
test() requires(!B);
};
template <>
test<true>::test()
{}
template <>
test<false>::test()
{}
int main()
{
test<false> a;
test<true> b;
return 0;
}
Demo
Clang:
error: out-of-line definition of '
test
' does not match any declaration in 'test<true>
'
Msvc:
error C2244: '
test<true>::test
': unable to match function definition to an existing declaration
You're declaring constrained constructors but defining two unconstrained specializations. Those won't ever match.
What you probably meant was:
template <bool B>
struct test
{
test() requires (B);
test() requires(!B);
};
template <bool B>
test<B>::test() requires (B)
{}
template <bool B>
test<B>::test() requires (!B)
{}
This compiles fine in all 3 compilers.
As to why your original version compiles - it's a GCC bug 96830. Clang is right, code is ill-formed because the out-of-line definitions don't match the template definition (note also that template<> ...
is full specialization syntax).
See [temp.class.general]/3 (emphasis mine):
When a member of a class template is defined outside of the class template definition, the member definition is defined as a template definition with the template-head equivalent to that of the class template.
[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.
Also see [temp.mem.func]/1 for an example of declaring a constrained member out-of-line:
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>
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