8

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.

18
  • 1
    "Can this be done?" => the compiler will tell you (no). As for the alternative solution, what exactly do you want to accomplish? Commented Feb 24, 2013 at 22:00
  • 2
    1. Did you try it? 2. What do want to do, exactly? Commented Feb 24, 2013 at 22:00
  • 9
    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. Commented Feb 24, 2013 at 22:04
  • 1
    @EdwardBird: That doesn't add much. How do you plan to use those nested enums? Why aren't plain enums enough? Why isn't it enough to use a namespace? What kind of comparisons, or assignments, do you intend to do? Commented Feb 24, 2013 at 22:12
  • 1
    @IInspectable IIRC, given this was asked 11 years ago, I believe I was trying to use enums both as a way of providing "an enum" as well as providing a hierarchical namespace structure. In other words, some enums should be not just the name for a type but also a namespace for other named types to live in. Since this time I still have not seen any examples of this being done in real code. Commented Jun 3, 2024 at 9:08

6 Answers 6

16

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
    };     
}
Sign up to request clarification or add additional context in comments.

8 Comments

That would be A::SOMETHING1; A::B::SOMETHING1 would require enum class B.
I did try it, hence the question.
@Neil: You sure? I think in C++11 this is allowed. This works for me
@Neil: See 7.2/10 of the C++11 Standard: there is an example that does just that.
It's worth noting that while A::B::SOMETHING1 works in C++11, the B:: is optional unless enum B is changed to enum class B, as Neil suggests.
|
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.

1 Comment

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.
1

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);
};

Comments

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)

1 Comment

Could you add some explanation? I am sure it will be much more helpful than just some code to other beginners (like me).
0

Nested enums are not directly supported but can be practially achieved is you define each 'nest' separately and then combine them. I worked on a project where I wanted to nest types of UI controls but differenciate them into groups. Here is a more generaic example just to explain my point:

#include <iostream>
#include <string>

// Define a class with nested enums and enum classes
class MyClass
{
public:
    // Nested enum within the class
    enum Color
    {
        Red,
        Green,
        Blue
    };

    // Nested enum class within the class
    enum class Size
    {
        Small,
        Medium,
        Large
    };

    // Static method to convert Color enum to string
    static std::string ColorToString(Color color)
    {
        switch (color)
        {
            case Red:
                return "Red";
            case Green:
                return "Green";
            case Blue:
                return "Blue";
            default:
                return "Unknown";
        }
    }

    // Static method to convert Size enum class to string
    static std::string SizeToString(Size size)
    {
        switch (size)
        {
            case Size::Small:
                return "Small";
            case Size::Medium:
                return "Medium";
            case Size::Large:
                return "Large";
            default:
                return "Unknown";
        }
    }
};

int main()
{
    // Using the nested enum
    MyClass::Color color = MyClass::Red;
    std::cout << "Color: " << MyClass::ColorToString(color) << std::endl;

    // Using the nested enum class
    MyClass::Size size = MyClass::Size::Medium;
    std::cout << "Size: " << MyClass::SizeToString(size) << std::endl;

    return 0;
}

Comments

-8

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

6 Comments

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)
@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?
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.
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).
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.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.