alain alain - 2 months ago 8
C++ Question

Inconsistent behavior of MSVC vs. GCC with sizeof

Consider the following code:

#include <cstddef>

class A
{
public:
struct B
{
int M;
};

static void StaticFunc();
};

void A::StaticFunc()
{
const std::size_t s0 = sizeof(::A::B::M);
const std::size_t s1 = sizeof(A::B::M);
const std::size_t s2 = sizeof(B::M);
}

int main()
{
const std::size_t s3 = sizeof(A::B::M);
return 0;
}


GCC compiles it, just warning about the unused variables.

Visual C++ 2015 however fails to compile it with:

error C2326: 'void A::StaticFunc(void)': function cannot access 'A::B::M'


on the lines

const std::size_t s0 = sizeof(::A::B::M);
const std::size_t s1 = sizeof(A::B::M);


in
StaticFunc()
.

The other line
s2 = ...
, and
s3 = ...
in
main()
compile fine.

Is this a bug in MSVC, or do I miss something basic here?

Answer

It is a bug in MSVC.

C++11/14 allows a non-static class member to be used in a non-evaluated context, see 5.1.1 [expr.prim.general] p. 13:

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

...

(13.3) — if that id-expression denotes a non-static data member and it appears in an unevaluated operand.

[ Example:

    struct S {
       int m;
    };
    int i = sizeof(S::m);        // OK
    int j = sizeof(S::m + 42);   // OK

— end example]

Edit: it looks like MSVC accepts B::M and doesn't accept A::B::M, which is a completely inexplicable behaviour. I don't see how it could be anything but a bug.

clang++ like g++ in C++11 and C++14 mode accepts the program. clang++ in C++03 mode rejects all 4 references to M (C++03 doesn't have anything like p. 13.3), whereas g++ in C++03 mode still accepts them (this is probably a g++ C++03 mode bug).