Constraints in C++20 are normalized before checked for satisfaction by dividing them on atomic constraints. For example, the constraint E = E1 || E2
has two atomic constrains E1
and E2
And substitution failure in an atomic constraint shall be considered as false value of the atomic constraint.
If we consider a sample program, there concept Complete = sizeof(T)>0
checks for the class T
being defined:
template<class T>
concept Complete = sizeof(T)>0;
template<class T, class U>
void f() requires(Complete<T> || Complete<U>) {}
template<class T, class U>
void g() requires(sizeof(T)>0 || sizeof(U)>0) {}
int main() {
f<void,int>(); //ok everywhere
g<void,int>(); //error in Clang
}
then the function f<void,int>()
satisfies the requirements, because Complete<void>
just evaluates to false
due to substitution failure and Complete<int>
evaluates to true
.
But a similar function g<void,int>()
makes the compilers diverge. GCC accepts it, but Clang does not:
error: no matching function for call to 'g'
note: candidate template ignored: substitution failure [with T = void, U = int]: invalid application of 'sizeof' to an incomplete type 'void'
void g() requires(sizeof(T)>0 || sizeof(U)>0) {}
Demo: https://gcc.godbolt.org/z/zedz7dMGx
Are the functions f
and g
not really identical, or Clang is wrong here?
This is Clang bug #49513; the situation and analysis is similar to this answer.
sizeof(T)>0
is an atomic constraint, so [temp.constr.atomic]/3 applies:
To determine if an atomic constraint is satisfied, the parameter mapping and template arguments are first substituted into its expression. If substitution results in an invalid type or expression, the constraint is not satisfied. [...]
sizeof(void)>0
is an invalid expression, so that constraint is not satisfied, and constraint evaluation proceeds to sizeof(U)>0
.
As in the linked question, an alternative workaround is to use "requires requires requires"; demo:
template<class T, class U>
void g() requires(requires { requires sizeof(T)>0; } || requires { requires sizeof(U)>0; }) {}
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