如果在一个概念的定义中(偶然地)提到了一个类的非静态数据成员,那么这个概念的期望值是什么?
比如说
struct B {
bool b;
};
template <typename T>
concept C1 = std::bool_constant<T::b>{}();
// #1 true in Clang and GCC, false in MSVC
static_assert( !C1<B> );
template <typename T>
concept C2 = T::b;
// #2 ok in Clang, errors in GCC and MSVC
static_assert( !C2<B> );
在这里,!C1<B>
在Clang和GCC中被计算为true
,在MSVC中被计算为false
。
在Clang中,!C2<B>
被计算为true
。但在GCC和MSVC中,这是一个硬错误。GCC:
error: '*(B*)(void)0' is not a constant expression
MSVC:
error C7607: atomic constraint should be a constant expression of type 'bool', not 'unknown'
在线演示:https://gcc.godbolt.org/z/eGds9nhTx
哪个编译器在这里?
1条答案
按热度按时间dvtswwa31#
GCC在这里是正确的。
非静态数据成员允许在未求值的操作数中不带对象使用[expr.prim.id.general]p(3.3):
表示类的非静态数据成员或隐式对象成员函数的 id-expression 只能用于:
[* 示例3:*
而在概念中带有
T = B
的T::b
的类型是bool
,即非静态数据成员的类型。显然,
B::b
不是bool
常量表达式,所以std::bool_constant<T::b>
是无效类型([temp.arg.nontype]p2,如果您确实需要引用),并且([expr.prim.req.general]p5):将模板参数替换到 requires-expression 中可能会导致在其 requirements 中形成无效的类型或表达式,或者违反那些 requirements 的语义约束。在这种情况下,requires-expression 的计算结果为
false
;它不会导致程序是病态的。所以
C1<B>
就是false
。但是,with
C2<B>
是一个原子约束,所以需要(withE = T::b
)[temp.constr.atomic]p3:E
应为bool
类型的常量表达式。...它不是一个常量表达式,所以这是一个硬错误。
Clang的错误是认为
T::b
在未评估的上下文中命名非静态数据成员是无效的,使C2<B>
具有无效的表达式并成为false
。MSVC的错误似乎是
T::b
被替换为常量表达式true
出于某种原因?