requires-表达式可以使用参数列表引入本地参数。如果这些参数中的任何一个具有
void
类型,则 require 表达式是否会产生 false
还是会出现硬编译错误?
考虑示例#1:
template<typename T>
concept C = requires(T t, void v) {
t;
};
static_assert(!C<int>);
Clang 和 MSVC 都接受,但 GCC 抱怨
错误:在参数声明中无效使用类型“void”
在线演示:https://gcc.godbolt.org/z/voMajE4K3
更简短的示例#2:
static_assert( requires(int t, void) {t;} );
再次被 Clang 接受,其中
requires
产生 true
。 GCC 发出同样的错误。 MSVC 现在打印:
错误 C2860:“void”不能用作除“(void)”之外的函数参数
在线演示:https://gcc.godbolt.org/z/eYbM49d7E
上面两个例子中哪个编译器是正确的?
所有编译器都是正确的。 requires-expression 中的无效参数类型会使 requires-expression 格式错误(不仅仅是 false),并且 [temp.res.general]/6.4 然后适用:
C程序格式错误,无需诊断,如果
- [...]
程序中的任何- 约束表达式,无论引入或以其他方式,都具有(以其正常形式)原子约束A,其中A的满足检查可能是格式良好的,并且A的满足检查不成立执行,或
[...]
的定义有requires-expression作为它的constraint-expression,前者是一个原子约束,所以它的正常形式就是它本身。当确定是否满足约束时,由于代入该原子约束总是会产生无效表达式,因此会触发上述规则,程序为 IFNDR。 有些人希望
requires-expression中的参数类型无效,以使 requires-expression 为 false,而不是格式错误 (CWG2565)。如果要进行这种更改,您的示例可能仍然是 IFNDR; [expr.prim.req.general]/5,当前为
如果将模板参数替换为需求参数声明子句总是会导致替换失败,则该程序是格式错误的;无需诊断。
可能会进行修改,以便它也适用于
。