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 ?
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
However, I must admit I personally would surely prefer what was recommended in the other answer.