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?