Adrian Cornish
Adrian Cornish

Reputation: 23858

Clang: error: invalid use of non-static data member

Is this gcc being overly nice and doing what the dev thinks it will do or is clang being overly fussy about something. Am I missing some subtle rule in the standard where clang is actually correct in complaining about this

Or should I use the second bit of code which is basically the how offsetof works

[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

Upvotes: 3

Views: 1237

Answers (1)

Anton Samsonov
Anton Samsonov

Reputation: 1422

I found adding -std=c++11 stops it complaining. GCC is fine with it in either version.

Modern GCC versions allow this even in -std=c++98 mode. However, older versions, like GCC 3.3.6 of mine, do complain and refuse to compile.

So now I wonder which part of C++98 I am violating with this code.

Wikipedia explicitly states that such a feature was added in C++11, and refers to N2253, which says that the syntax was not considered invalid by the C++98 standard initially, but then intentionally clarified to disallow this (I have no idea how non-static member fields are any different from other variables with regard to their data type). Some time later they decided to make this syntax valid, but not until C++11.

The very same document mentions an ugly workaround, which can also be seen throughout the web:

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

It looks like simply using 0, NULL or nullptr may trigger compiler warnings for possible dereference of a null pointer (despite the fact that sizeof never evaluates its argument), so an arbitrary non-zero value might be used instead, although it will look like a counter-intuitive “magic constant”. Therefore, in my C++ graceful degradation layer I use:

#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

Usage examples:

// 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)

By the way, note the syntax difference for sizeof(Type) and sizeof Expression, as they are formally not the same, even if sizeof(Expression) works — as long as sizeof (Expression) is valid. So, the most correct and portable form would be sizeof(decltype(Expression)), but unfortunately it was made available only in C++11; some compliers have provided typeof(Expression) for a long time, but this never was a standard extension.

Upvotes: 1

Related Questions