在 C++03 的未评估上下文中使用表示非静态数据成员的 id 表达式是否有效

Is it valid to use an id-expression representing a non-static data member in an unevalauted context in C++03

给定以下代码:

#include <iostream>

struct A
{
    int x ;
} ;

int main()
{
    std::cout << sizeof( A::x ) << "\n" ;
}

clang(see it live) and gcc(see it live) 不同意这在 C++03 中是否有效。 clang 提供以下诊断:

error: invalid use of non-static data member 'x'
std::cout << sizeof( A::x ) << "\n" ;
                     ~~~^

gcc 没有为这个例子生成诊断。

clang 和 gcc 在 C++11 及更高版本中都接受此代码。我们可以从 C++11 标准草案 5.1.1 [expr.prim.general] 中看到这在 C++11 中是有效的,它说:

An id-expression that denotes a non-static data member or non-static member function of a class can only be used:

并包括以下项目符号:

  • if that id-expression denotes a non-static data member and it appears in an unevaluated operand

N1804 2005 年可用的最早的 C++ 标准草案似乎没有类似的措辞。

这在 C++03 中有效吗,哪个编译器是正确的?

这在 C++03 中无效,尽管这通过 defect report 613: Unevaluated uses of non-static class members 改变了,它说:

According to 9.2 [class.mem] paragraph 9, the name of a non-static data member can only be used with an object reference (explicit or implied by the this pointer of a non-static member function) or to form a pointer to member. This restriction applies even in the operand of sizeof, although the operand is not evaluated and thus no object is needed to perform the operation. Consequently, determining the size of a non-static class member often requires a circumlocution like

sizeof ((C*) 0)->m

instead of the simpler and more obvious (but incorrect)

sizeof (C::m)

The CWG considered this question as part of issue 198 and decided at that time to retain the restriction on consistency grounds: the rule was viewed as applying uniformly to expressions, and making an exception for sizeof would require introducing a special-purpose “wart.”

我们可以在 N2253 中找到措辞,其中引入了术语 未计算的操作数

我们可以看到 gcc 决定将其应用回 C++03,因为它已通过缺陷报告进行了更改。这是错误报告 [C++03]sizeof(qualified-id) accepted when the operand denotes a non-static member 中的文档,其中包含以下示例:

struct Tag { int m; };

int main()
{
    sizeof(Tag::m);
}

并说:

According to ISO C++03 5.1/10, this is not well-formed. (But C++11 should work.) However, G++ 4.9.1 wrongly accepted it even with -std=c++03 -pedantic-errors.

结论是这不是错误:

It has always been the policy of G++ (and other compilers!) to incorporate DRs into past standard modes, and that is clearly documented in the manual:

c++98
c++03
  The 1998 ISO C++ standard plus the 2003 technical corrigendum
  and some additional defect reports.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

So this is not a bug and there is no documentation issue.

这个缺陷有 CD1 status,根据我的经验,一般来说,缺陷也适用于标准的以前版本。不清楚我们是否可以说 clang 不正确而不将其应用回去,尽管它会产生更一致的行为。