Clang:错误:非静态数据成员的使用无效



这个gcc是太好了,做了开发人员认为它会做的事情,还是clang对某些事情过于挑剔。我是不是错过了标准中的一些微妙规则,在这些规则中,clang抱怨这个实际上是正确的

或者我应该使用代码的第二位,这基本上是offsetof如何工作的

[adrian@localhost ~]$ g++ -Wall -pedantic -ansi a.cc
[adrian@localhost ~]$ a.out
50
[adrian@localhost ~]$ cat a.cc
#include <iostream>
struct Foo
{
   char name[50];
};
int main(int argc, char *argv[])
{
   std::cout << sizeof(Foo::name) << std::endl;
   return 0;
}

[adrian@localhost ~]$ clang++ a.cc
a.cc:10:29: error: invalid use of non-static data member 'name'
   std::cout << sizeof(Foo::name) << std::endl;
                       ~~~~~^~~~
1 error generated.
[adrian@localhost ~]$ g++ -Wall -pedantic -ansi b.cc
[adrian@localhost ~]$ a.out
50
[adrian@localhost ~]$ cat b.cc
#include <iostream>
struct Foo
{
   char name[50];
};
int main(int argc, char *argv[])
{
   std::cout << sizeof(static_cast<Foo*>(0)->name) << std::endl;
   return 0;
}

[adrian@localhost ~]$ clang++ b.cc
[adrian@localhost ~]$ a.out
50

我发现添加-std=c++11可以阻止它抱怨。GCC很好无论是哪种版本。

即使在-std=c++98模式下,现代GCC版本也允许这样做。然而,较旧的版本,如我的GCC 3.3.6,确实抱怨并拒绝编译。

所以现在我想知道我用这段代码违反了C++98的哪一部分。

维基百科明确表示,这样的功能是在C++11中添加的,并引用了N2253,N2253表示,最初C++98标准并不认为该语法无效,但后来故意澄清不允许这样做(我不知道非静态成员字段在数据类型方面与其他变量有什么不同)。一段时间后,他们决定使这种语法有效,但直到C++11。

同一份文件提到了一个丑陋的解决方法,也可以在整个网络上看到:

sizeof(((Class*) 0)->Field)

看起来,简单地使用0NULLnullptr可能会触发编译器警告,因为可能会取消引用空指针(尽管sizeof从未评估其参数),因此可能会使用任意的非零值,尽管它看起来像是一个反直觉的"魔术常数"。因此,在我的C++优雅降级层中,我使用:

#if __cplusplus >= 201103L
    #define CXX_MODERN 2011
#else
    #define CXX_LEGACY 1998
#endif

#ifdef CXX_MODERN
    #define CXX_FEATURE_SIZEOF_NONSTATIC
    #define CxxSizeOf(TYPE, FIELD) (sizeof TYPE::FIELD)
#else
    // Use of `nullptr` may trigger warnings.
    #define CxxSizeOf(TYPE, FIELD) (sizeof (reinterpret_cast<const TYPE*>(1234)->FIELD))
#endif

用法示例:

// On block level:
class SomeHeader {
public:
    uint16_t Flags;
    static CxxConstExpr size_t FixedSize =
#ifdef CXX_FEATURE_SIZEOF_NONSTATIC
        (sizeof Flags)
#else
        sizeof(uint16_t)
#endif
    ;

}; // end class SomeHeader

// Inside a function:
void Foo(void) {
    size_t nSize = CxxSizeOf(SomeHeader, Flags);
} // end function Foo(void)

顺便说一句,注意sizeof(Type)sizeof Expression的语法差异,因为它们在形式上不相同,即使sizeof(Expression)有效——只要sizeof (Expression)有效。因此,最正确和可移植的形式是sizeof(decltype(Expression)),但不幸的是,它只能在C++11中使用;一些编译器提供typeof(Expression)已经有很长一段时间了,但这从来都不是一个标准的扩展。

最新更新