c++ 概念定义中的非静态数据成员

7bsow1i6  于 2023-07-01  发布在  其他
关注(0)|答案(1)|浏览(121)

如果在一个概念的定义中(偶然地)提到了一个类的非静态数据成员,那么这个概念的期望值是什么?
比如说

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
哪个编译器在这里?

dvtswwa3

dvtswwa31#

GCC在这里是正确的。
非静态数据成员允许在未求值的操作数中不带对象使用[expr.prim.id.general]p(3.3):
表示类的非静态数据成员或隐式对象成员函数的 id-expression 只能用于:

  • [...]
  • 如果 id-expression 表示非静态数据成员且它出现在未求值操作数中。

[* 示例3:*

struct S {
  int m;
};
int i = sizeof(S::m);           // OK
int j = sizeof(S::m + 42);      // OK
    • 结束示例 *]
      而在概念中带有T = BT::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>是一个原子约束,所以需要(with E = T::b)[temp.constr.atomic]p3:
      E应为bool类型的常量表达式。
      ...它不是一个常量表达式,所以这是一个硬错误。
      Clang的错误是认为T::b在未评估的上下文中命名非静态数据成员是无效的,使C2<B>具有无效的表达式并成为false
      MSVC的错误似乎是T::b被替换为常量表达式true出于某种原因?

相关问题