Murilo Maestro
Murilo Maestro

Reputation: 69

Is there a way to nest enums in c++ without namespace?

I'm implementing a byte code generator for a given AST. While creating the expression class I noticed the distincition between unary and binary operators. For simplicity unum was the go-to solution, so I nested the enuns this way:

enum EXP_TYPE
{
    enum BINARY
    {
        PLUS,
        MINUS,
        MULTIPLY,
        DIV,
        ...
    };
    enum UNARY
    {
        PLUS,
        MINUS,
        POINTER,
        INC,
        ...
    };
};

Of course this code throws warnings informing this is not allowed. So I searched a bit on stackoverflow and other sources, and found the solution of using namespace instead of enum for EXP_TYPE declaration. But the problem now is the use inside the expression class:

class expression
{
    expression *right_exp;
    expression *left_exp;
    EXP_TYPE type;
    ...
};

The use of EXP_TYPE is not allowed anymore due to it being a namespace instead of a enum type. What I intented to make was a generic enum declaration that could be used as a atribute inside a class, in here generic means that it could be BINARY or UNARY, that is, the atribute EXP_TYPE type could have assignments and comparisons like:

 expression exp1;
 exp1.type = EXP_TYPE::BINARY::PLUS;
 exp1.type = EXP_TYPE::UNARY::PLUS;

Is there a way to make these simple generic types without using namespace in the way presented, or without the need of creating a class hierarchy for unary and binary operators ?

Upvotes: 2

Views: 143

Answers (2)

Scheff's Cat
Scheff's Cat

Reputation: 20141

I took this as puzzle to find out how close I could come to what the OP requested.

This is what I got (though I must admit it looks a bit scaring):

#include <cassert>
#include <iostream>

struct ExpType {
  struct Unary {
    enum {
      Plus, Minus, Pointer, Inc,
      N
    };
  };
  struct Binary {
    enum {
      Plus = Unary::N, Minus, Multiply, Div,
      N
    };
  };
  enum {
    N = Binary::N
  };

  int value;

  ExpType(int value = 0): value((assert(value >= 0 && value < N), value)) { }
  ~ExpType() = default;
  ExpType(const ExpType&) = default;
  ExpType& operator=(const ExpType&) = default;

  operator int () { return value; }
};

int main()
{
  for (int i = 0; i < ExpType::N; ++i) {
    ExpType expType = i;
    switch (expType) {
#define CASE(TYPE) case TYPE: std::cout << #TYPE "\n"; break
      CASE(ExpType::Unary::Plus);
      CASE(ExpType::Unary::Minus);
      CASE(ExpType::Unary::Pointer);
      CASE(ExpType::Unary::Inc);
      CASE(ExpType::Binary::Plus);
      CASE(ExpType::Binary::Minus);
      CASE(ExpType::Binary::Multiply);
      CASE(ExpType::Binary::Div);
#undef CASE
      default: std::cout << "Unknown expression type!\n";
    }
  }
}

Output:

ExpType::Unary::Plus
ExpType::Unary::Minus
ExpType::Unary::Pointer
ExpType::Unary::Inc
ExpType::Binary::Plus
ExpType::Binary::Minus
ExpType::Binary::Multiply
ExpType::Binary::Div

Live Demo on coliru

However, I must admit I personally would surely prefer what was recommended in the other answer.

Upvotes: 3

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385174

No, you cannot create scopes inside of enums.

Instead, categorise your enumerations with longer names (e.g. EXP_TYPE::BINARY_PLUS).

Upvotes: 6

Related Questions