What does “static enum” mean in C++?

2020-02-08 11:40发布

问题:

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,
    ...
};

回答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;


回答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.



回答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?



回答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:

  • related question for static struct in C: Why and when to use static structures in C programming?


回答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 ** */


回答6:

Im not sure why static was used or why it even compiles. Should just be enum Response. Enumerators are not static data.