What does "static enum" mean in C++?

45,026

Solution 1

That exact code, with just the ellipsis removed, is not valid C++. You can't use the static storage class specifier in an enum declaration; it doesn't make any sense there (only objects, functions, and anonymous unions can be declared static).

You can, however, declare an enum and a variable all in one declaration:

static enum Response {
    NO_ERROR = 0,
    MISSING_DESCRIPTOR
} x; 

The static here applies to x and it is effectively the same as if you said:

enum Response { 
    NO_ERROR = 0,
    MISSING_DESCRIPTOR
};

static Response x;

Solution 2

Surprisingly you can put other decl-specifiers in there too.
This compiles fine in VS2008:

auto const enum TestEnum {
    Why,
    Does
};

register volatile enum TestEnum2 {
    This,
    Work
};

But it makes no sense at all :)

I suspect the problem here is in the parsing, because code like this:

enum TestEnum3 { Hello, World };  // Define enum
enum TestEnum3 x = World;         // Use enum

Could also be written as:

enum TestEnum3 { Hello, World } x = World; // Define and use enum.

Interestingly, I notice if you do this in VS2008:

enum TestEnum3 { Hello, World };
const enum TestEnum3 e3 = World;
const enum TestEnum4 { F, M, L } e4 = F;

e3 = Hello; // error C2166: l-value specifies const object (Good!)
e4 = M;     // NO ERROR here though - why?

So they are not equivalent as in the TestEnum4 case it seems to be throwing away the const decl-specifier. All very odd.

Solution 3

static enum Response { /*... */ };

You cannot define static enum in C++. static can only be the variable of the enum, not the type itself!

Compiling your code with GCC version 4.3.4, it gives this error:

prog.cpp:7: error: a storage class can only be specified for objects and functions

See yourself online at ideone: http://www.ideone.com/cI1bt

I think that says it all.

--

However, if you want to limit the type enum Response in it's own translation unit, then you can use unnamed namespace. Have a look at this topic:

Superiority of unnamed namespace over static?

Solution 4

Standard

The C++11 N3337 standard draft Annex C 7.1.1 says that it was allowed in C but had no effect, and became illegal in C++:

Change: In C ++, the static or extern specifiers can only be applied to names of objects or functions. Using these specifiers with type declarations is illegal in C ++. In C, these specifiers are ignored when used on type declarations. Example:

static struct S {    // valid C, invalid in C++
  int i;
};

Rationale: Storage class specifiers don’t have any meaning when associated with a type. In C ++, class members can be declared with the static storage class specifier. Allowing storage class specifiers on type declarations could render the code confusing for users.

And like struct, enum is also a type declaration.

Implementation rationale

Enum definitions have no storage, and do no generate symbols in object files like variables and functions. Just try compiling and decompiling:

struct S { int i; int j; };
int i;

with:

g++ -c main.c
nm main.o

and you will see that there is no S symbol, but there is an i symbol.

When the compiler sees an enum values, it just inserts it literally into the compiled code. This only works of course because they are compile-time constants.

They must therefore be included on header files.

See also:

Solution 5

In C#:

The ';' is optional for backwards compatibility after the enum block. It does not allow for such semantics in that language for named types. static, public, etc. have special consideration. Namespace cannot contain members such as fields or methods.

Requires tag:

ArgTypes var = ArgTypes.CUT;

In C/C++:

Requires ';' at the end of enum block. For global namespace variables, enumerations, etc. static is by default.

int type;

typedef enum {
  TOKENIZE,
  CUT
} ArgTypes;
type = TOKENIZE;  /* <ArgTypes>::TOKENIZE */
type = ArgTypes::CUT;

// Recommended Use
enum ArgTypes {
  TOKENIZE,
  CUT
};  /* Same as above */

enum Test {
  TOKENIZE,
  CUT
} ArgTypes;
type = ArgTypes::TOKENIZE;
type = CUT;   /* Assign type =>  <Test>.CUT */
type = Test::CUT;

enum {
  TOKENIZE,
  CUT
} ArgTypes;  /* Unamed.. requires tag */
type = TOKENIZE; /* <unamed>.TOKENIZE=0 => #define TOKENIZE 0*/
type = ArgTypes::TOKENIZE;  /* ** ERROR ** */
Share:
45,026
Marcin K
Author by

Marcin K

Updated on February 21, 2020

Comments

  • Marcin K
    Marcin K about 4 years

    I recently came across this:

    static enum Response{
        NO_ERROR=0,
        MISSING_DESCRIPTOR,
        ...
    };
    

    It compiles and works under Microsoft VS2005. However, I'm not sure what the 'static' modifier is supposed to do. Is it any different from the following?

    enum Response {
        NO_ERROR=0,
        MISSING_DESCRIPTOR,
        ...
    };
    
  • Marcin K
    Marcin K over 13 years
    Apparently, in this particular flavour of C++, one can do that. However, your comment abou the unnamed namespace is very interesting, thanks!
  • Nawaz
    Nawaz over 13 years
    @Marcin: No, you cannot do that. VS2005 incorrectly compiles that. Read James' reply; he explained when you can write static enum and more importanly what exactly it means. It makes the variable static, not the type itself.
  • Marcin K
    Marcin K over 13 years
    According to this, it seems they really have a bug in the parser then. Thanks for this example with 'auto const'.
  • PlasmaHH
    PlasmaHH about 12 years
    My guess would be that since this was valid in C, msvc just forgot to implement this properly when evolving into a c++ compiler