9

Can this be done?

enum A
{
    enum B
    {
        SOMETHING1,
        SOMETHING2
    };

    enum C
    {
        SOMETHING3,
        SOMETHING4
    };
};

If not is there an alternative solution?

The purpose of this question: Want/need to be able to do something like this:

enum class ElementaryParticleTypes
{

    enum class MATTER
    {
        enum class MESONS
        {
            PI
        };

        enum class BARYONS
        {
            PROTON,
            NEUTRON
        };

        enum class LEPTONS
        {
            ELECTRON
        };
    };

    enum class ANTI_MATTER
    {
        enum class ANTI_MESONS
        {
            ANTI_PI
        };

        enum class ANTI_BARYONS
        {
            ANTI_PROTON
            ANTI_NEUTRON
        };

        enum class ANTI_LEPTONS
        {
            POSITRON
        };
    };

};

Wish to use the strongly-typed capabilities.

congusbongus
  • 13,359
  • 7
  • 71
  • 99
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • 1
    "Can this be done?" => the compiler will tell you (no). As for the alternative solution, what exactly do you want to accomplish? – Jon Feb 24 '13 at 22:00
  • 2
    1. Did you try it? 2. What do want to do, exactly? – Carl Norum Feb 24 '13 at 22:00
  • What happens when you compile this code? – Code-Apprentice Feb 24 '13 at 22:01
  • Compiler gives me the error: expected identifier before ‘enum’, error: expected ‘}’ before ‘enum’, error: expected identifier before ‘enum’, error: expected ‘}’ before ‘enum’, error: multiple types in one declaration, error: expected declaration before ‘}’ token – FreelanceConsultant Feb 24 '13 at 22:04
  • 8
    In fairness, just because something doesn't compile with one compiler and one set of compiler options doesn't mean that it's not in the standard. – johnsyweb Feb 24 '13 at 22:04
  • Exactly the reason for my question - I am wondering if there is a way of doing it. Why else would I ask? @CarlNorum Who posts a question like this unless they had already tried it? – FreelanceConsultant Feb 24 '13 at 22:06
  • 1
    @EdwardBird: That doesn't add much. How do you plan to *use* those nested `enum`s? Why aren't plain `enum`s enough? Why isn't it enough to use a namespace? What kind of comparisons, or assignments, do you intend to do? – Andy Prowl Feb 24 '13 at 22:12
  • +1 @Andy, and SO is *filled* with questions from people who didn't try anything before asking. – Carl Norum Feb 24 '13 at 22:12
  • The enum is simply a flag to be passed to a class on construction. It doesn't make sense to construct a particle without a type. – FreelanceConsultant Feb 24 '13 at 22:13
  • It looks like you're trying to have some kind of inheritance for enums? Why not just make classes? – Carl Norum Feb 24 '13 at 22:13
  • No. I might as well pass in an unsigned integer than have all the extra overhead. It makes absolutely no sense to use a class as a flag. – FreelanceConsultant Feb 24 '13 at 22:17
  • @EdwardBird: So what's wrong with namespaces? – Andy Prowl Feb 24 '13 at 22:17
  • It's a solution. Just thought it made more sense to use an enum, because it will auto assign me unique numbers to each item. Also - strong typing. I mean, enums are here for this purpose. – FreelanceConsultant Feb 24 '13 at 22:21
  • @EdwardBird: Yes, but `enum`s are lists of alternative *values*, not lists of alternative `enum`s (a member of an `enum` is a value, not a type), and the kind of "hierarchy of `enum`s" you are trying to set up is something that (in C++) doesn't make sense. – Andy Prowl Feb 24 '13 at 22:23
  • @AndyProwl Yeah this is why I suspected it would not compile. AND IT DIDNT – FreelanceConsultant Feb 24 '13 at 22:30

5 Answers5

15

No, they cannot be nested that way. In fact, any compiler would reject it.

If not is there an alternative solution?

That mostly depends on what you are trying to achieve (solution to what problem?). If your goal is to be able to write something like A::B::SOMETHING1, you could just define them within a namespace, this way:

namespace A
{
    enum B
    {
        SOMETHING1,
        SOMETHING2
    };

    enum C
    {
        SOMETHING3,
        SOMETHING4
    };     
}
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
3

Seeing that in this particular case, the enumerations aren’t likely to change often, you could go for:

namespace ParticleTypes {
    namespace Matter {
        enum Mesons {
            Pi
        };

        enum Baryons {
            Proton = Pi + 1,
            Neutron
        };

        enum Leptons {
            Electron = Neutron + 1
        };
    }

    namespace AntiMatter {
        enum AntiMesons {
            AntiPi = Matter::Electron + 1
        };

        // ...
    }
}

I do wonder, however, why you want different enum types for different types of particles. Do you have functions which accept an argument of type Mesons, but not of type Leptons? If not, and all your functions accept any of the particles, then use a single enum – and preferably, drop the long prefixes to the names of the values like MATTER_MESONS_, MATTER_BARYONS_ etc.

Lumen
  • 3,554
  • 2
  • 20
  • 33
  • This has the same problems are other solutions. If I wish to add a particle for example. Also your comment about a single enum has been discussed. – FreelanceConsultant Feb 25 '13 at 09:56
0
MESONS pi = PI();
MATTER mat = pi;
assert (pi == mat);

Do you mind a little C++11 template magic?

template <typename T, typename... L>
struct is_defined_in : std::false_type {};

template <typename T, typename U, typename... L>
struct is_defined_in<T, U, L...> : is_defined_in<T, L...> {};

template <typename T, typename... L>
struct is_defined_in<T, T, L...> : std::true_type {};

template <int ID> struct helper {
  friend bool operator==(helper a, helper b)
  { return a.id == b.id; }
  friend bool operator!=(helper a, helper b)
  { return a.id != b.id; }

  int id=ID;
};
template <typename... B> struct category {
  int id;

  template <typename T,
            typename = typename std::enable_if<is_defined_in<T, B...>::value>::type>
  category(T t) : id(t.id) {}

  friend bool operator==(category a, category b)
  { return a.id == b.id; }
  friend bool operator!=(category a, category b)
  { return a.id != b.id; }
};

enum class ElementaryParticleTypesID
{ PI, PROTON, NEUTRON, ELECTRON };

struct PI       : helper<(int)ElementaryParticleTypesID::PI> {};
struct PROTON   : helper<(int)ElementaryParticleTypesID::PROTON> {};
struct NEUTRON  : helper<(int)ElementaryParticleTypesID::NEUTRON> {};
struct ELECTRON : helper<(int)ElementaryParticleTypesID::ELECTRON> {};

using MESONS = category<PI>;
using BARYONS = category<PROTON, NEUTRON>;
using LEPTONS = category<ELECTRON>;

using MATTER = category<MESONS, BARYONS, LEPTONS>;

(the static_assert currently doesn't work beyond two hierarchies, but this can be added if you want to)

ipc
  • 8,045
  • 29
  • 33
0

Say, you have this problem inside a class. You can't use namespaces here. Therefore, use a struct:

class Locations {
public:
    explicit Locations();

    struct Locations {
        enum class Folder {
            Db,
            Export,
            Copy,
        };

        enum class Filename {
            Db,
            Export,
            Copy,
        };

        enum class Path {
            Db,
            Export,
            Copy,
        };
    };

    void setLocation(Locations::Folder fld);
    void setLocation(Locations::File file);
    void setLocation(Locations::Path path);
};
Mykola Tetiuk
  • 153
  • 1
  • 13
-5

There is (still) no way of doing this (in 2023). The closest you can get is to define everything in a long list inside one enum.

enum class A{
  PARTICLE_MATTER_BARYON_PROTON,
  PARTICLE_MATTER_BARYON_NEUTRON,
  PARTICLE_ANTIMATTER_BARYON_PROTON // etc
};
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • 7
    This answer is just not correct. You can use namespaces, which would give you the desired nesting. I'm not saying you have to accept my answer, but if you post your own answer with the sole purpose of not accepting any other answer, at least make sure it is correct. (Btw, I am not the downvoter) – Andy Prowl Feb 24 '13 at 22:38
  • @AndyProwl That is not the same as this solution. At least using this method I do not have to watch out for using the same value twice, which is more of a problem than the nesting. Therefore this solution is better than your one. Since I am asking the question, I am also the judge of the best solution for me. So why the necessary down vote? – FreelanceConsultant Feb 24 '13 at 22:46
  • 1
    If you'd use enum classes inside the namespace, you wouldn't have to care about the values across different enums, unless you did something stupid like casting them. – Xeo Feb 24 '13 at 22:55
  • @EdwardBird: As I said, I am not the one who cast the downvote, so do not ask me. – Andy Prowl Feb 24 '13 at 22:56
  • 1
    I didn't downvote but I'd hazard a guess that whomever did so did so because of "I am accepting this as the answer to stop further notifications from stackoverflow asking me to accept an answer". What a ridiculous way to use Stack Overflow (that's how it's spelt, by the way). – Lightness Races in Orbit Feb 24 '13 at 22:58
  • 1
    I placed the downvote because as it stands, I can't see how this answers the question stated. SO is not only for the benefit of questioners, it is also for people in the future looking for answers to the same questions. You haven't clearly explained how you'll use these enums, why you need them to have separate values etc. – congusbongus Feb 24 '13 at 23:03