模板函数的原子约束require -clause中的替换失败



c++ 20中的约束是标准化的,然后通过在原子约束上划分它们来检查是否满足。例如,约束E = E1 || E2有两个原子约束E1E2

原子约束中的替换失败应视为原子约束的假值。

如果我们考虑一个示例程序,有concept Complete = sizeof(T)>0检查正在定义的类T:

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
}

则函数f<void,int>()满足要求,因为Complete<void>由于替换失败只求值为false,Complete<int>求值为true

但是一个类似的函数g<void,int>()使编译器产生分歧。GCC接受它,但Clang不接受:

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) {}

演示:https://gcc.godbolt.org/z/zedz7dMGx

函数fg不是真的相同,或者Clang在这里是错误的?

Clang bug #49513;情况和分析与这个答案相似。

sizeof(T)>0是一个原子约束,所以[temp.constr. cn]原子)/3适用:

要确定是否满足原子约束,首先将形参映射和模板实参替换到其表达式中。如果替换导致无效的类型或表达式,则不满足约束。[…]

sizeof(void)>0是无效表达式,因此约束不满足,约束继续求值到sizeof(U)>0

与链接的问题一样,另一种解决方法是使用">requires requires";演示:
template<class T, class U>
void g() requires(requires { requires sizeof(T)>0; } || requires { requires sizeof(U)>0; }) {}

最新更新