1

I have such code:

class A
{
public:

    unsigned long a;
    static const unsigned long b = sizeof(a); // "error C2327: 'A::a' : is not a type name, static, or enumerator" in VC++
};

I got compiler error in VC++ and no errors in IAR. Which compiler is right, what C++ standart says about it?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
vadim b.
  • 31
  • 3

4 Answers4

1

Your MSVS versions are quite old, so based on that, and assuming they default to C++03, they are correct to reject your code. I'll quote n1905, which for our purposes is pretty close to the C++03 standard.

9.4 [class.static] (emphasis mine)

If an unqualified-id (5.1) is used in the definition of a static member following the member’s declarator-id, and name lookup (3.4.1) finds that the unqualified-id refers to a static member, enumerator, or nested type of the member’s class (or of a base class of the member’s class), the unqualified-id is transformed into a qualified-id expression in which the nested-name-specifier names the class scope from which the member is referenced. The definition of a static member shall not use directly the names of the non-static members of its class or of a base class of its class (including as operands of the sizeof operator). The definition of a static member may only refer to these members to form pointer to members (5.3.1) or with the class member access syntax (5.2.5).

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
1

StoryTeller's answer specifies why this didn't work on . Namely because it wasn't supported until .

As far as it's not fully compliant. But I've validated that this code works around the deficiency:

static const unsigned long b = sizeof(decltype(a))

If you want something that will work with as well, consider making b a global, instead of a static member of A:

const unsigned long b = sizeof(A().a)
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    Keyword is *should*. And I'm not sure C++11 was the default standard for MSVC2013 back then. – StoryTeller - Unslander Monica Nov 28 '18 at 14:19
  • 1
    According to [this source](https://msdn.microsoft.com/en-us/library/hh567368.aspx), C++11 is not entirely supported even in MSVC2015. – Algirdas Preidžius Nov 28 '18 at 14:21
  • @AlgirdasPreidžius You're not wrong... Even VS2015 has some outstanding C++11 deficiencies. Or maybe I should just say C++ standard deficiencies :( I'll reword just to be clear. What I was trying to communicate is that `sizeof(a)` is actually valid code now... It's just a Visual Studio discrepancy that prevented it from compiling. – Jonathan Mee Nov 28 '18 at 14:30
  • @StoryTeller Yeah, I've clarified. As has been pointed out VS2013 didn't even claim to be C++11 compliant. – Jonathan Mee Nov 28 '18 at 14:33
0

What do you have?

You have the definition of a class named A.

Your class has a unsigned long named a.

Your class has a static const unsigned long named b.

In certain C++ compilers, static and non-static members of a class can't be mixed, specially in the definition stage.

What do you want?

static const unsigned long b = sizeof(unsigned long);

This is not exactly what you want, but this is how a smart compiler try to figure out.

WHY???

Because static members doesn't limit their scope to the object definition. They overpass the object scope and can be accessed from everywhere simply outputting A::b in the console using std::cout << A::b << std::endl, for example.

Clang doesn't accept this construction, GCC does (both with -g -std=c++98)

MSVC 19.14 (visual studio 15.7) doesn't accept it, too, but visual studio 15.8, with MSVC 19.15, does.

Choose carefully.

Where I check all this stuff?

Here I check lots of compilers: https://godbolt.org/ This is one method, but you must evade this kind of hacks in the future.

Magic code to check and blame

The blame part is for mixing C and C++. It's only for compile with older versions without any checks:

#include <stdio.h>

class A
{
public:

    unsigned long a;
    static const unsigned long b = sizeof(a); // "error C2327: 'A::a' : is not a type name, static, or enumerator" in VC++
};

int main (void)
{
    printf ( "Hello World" ); // I strongly not recommend using printf's in C++ code. 
    printf ( "%d", A::b );    // This is only to fill a functional example, not a rightful one.
    return 0;
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • This answer does provide some circumstantial evidence of which behavior is correct. As such I feel bad about the fact someone downvoted here, especially when such effort was put into this answer. So have a +1. – Jonathan Mee Nov 28 '18 at 14:46
  • I don't feel bad about downvoting. I'm feeling good somebody could read it and understands it, even if they downvote or upvote that. The standards are not the real world, but the compilers out there, are. – José Manuel Ramos Dec 06 '18 at 12:07
0

static const-qualified member in-class initialisers using non-static members were not part of the C++ standard until C++11.

The earliest MSVC compiler that fully supports C++11 is MSVC2017.

That compiler will compile your code correctly.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • I believe this to be correct (though I don't have VS2015 to check.) I just couldn't figure out the feature name that Microsoft gave to this portion of the spec, so I couldn't find anything authoritative on the timeline in which support was gained. [`decltype` can be used to workaround this deficiency circa VS 2012](https://stackoverflow.com/a/53521388/2642059). So I'd really like to read about the limitation... If you could provide a link to source your statements it's worth a +1 to ya! – Jonathan Mee Nov 28 '18 at 15:27
  • 1
    @JonathanMee: Informally, you could check the value of __cplusplus on the compiler: MSVC2017 is the earliest one that has this to a C++11 value. Probably only worth 1/2 in integer arithmetic ;-) – Bathsheba Nov 28 '18 at 15:43