Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intuitive way to make something like a member function for an enum class (C++11)

Tags:

c++

enums

c++11

Near as I can tell the ideal thing I'm looking for is outside of the C++11 spec, which would be something like where if I otherwise had something like an enum class where the core of it would look this something like this:

enum class Color { RED, ORANGE, YELLOW, GREEN, CYAN, AZURE, BLUE, MAGENTA };

I ideally would have wanted to have (non-virtual) member functions such that I could define something like this:

Color Color::complement() const
{
  switch(*this) {
    case RED:return CYAN;
    case ORANGE: return AZURE;
    case YELLOW: return BLUE;
    case GREEN: return MAGENTA;
    case CYAN: return RED;
    case AZURE: return ORANGE;
    case BLUE: return YELLOW;
    case MAGENTA: return GREEN;
  }
}

Of course, the C++11 spec doesn't allow you to define member functions for enum classes, so this is not possible.

Now strictly speaking, I don't really require my complement function to actually be regular member function, specifically, but if it could not be, then I ideally would want it to somehow still be specified using Color:: for scope resolution. Even a static member function would have been fine, taking a Color argument as a parameter, but again... C++11 does not allow you to have even static member functions in an enum class.

One option that had occured to me was to sacrifice this the preference for explicitly specifying Color:: in the name, and define a function at the same level as the Color enum as follows:

Color complement(Color orginal) 
{
  switch(orginal) {
  ...
  }
}

The biggest problem I have with this approach is that this complement function is not bound to the class namespace of Color, and although argument checking assures that it won't be used in another context, I feel that code that utilizes the function would be clearer to the reader of the code if the function were called via Color::complement, which in my opinion reads much more idiomatically than simply complement. Further, such encoding of the type into how one calls this function is actually enforced by the compiler itself (the ideal, in my opinion, since it does not necessitate that the function name be anything more than a predicate to be very clear to one who is reading the code on what the function's purpose is and how it is to be used), and the name cannot get inadvertently deprecated if the underlying types should change, which is my biggest problem with trying to use a naming scheme that somehow encodes the names of datatypes into the names of the identifiers themselves.

I had briefly also considered just using namespaces, like so:

namespace Color
  enum  { RED, ORANGE, YELLOW, GREEN, CYAN, AZURE, BLUE, MAGENTA };
  int complement(int orginal)
  {
    switch(original) {
     ....
    }
  }
}

Which would allow me to specify colors as Color::RED, Color::BLUE, etc, as well as be able to specify something like Color::complement(x) to get the complement of the color contained in x, but this approach does not have strong type checking that an enum class does. If I used an enum class inside of the Color namespace itself, then I would be forced to specify colors as Color::additional_name::RED, etc... instead of just Color::RED, which is how I want to be able to specify them.

C++ does not allow me to have both an enum class called Color and a namespace Color, so there is no way to syntactically achieve what I am after that way either.

So... is there a way to achieve the scoping that I would like, with the strong type-checking that I want, or am I just hosed, and expecting more of the language than what it is really designed to do?

like image 328
markt1964 Avatar asked Aug 16 '15 17:08

markt1964


People also ask

Can you add methods to an enum class?

The enum class body can include methods and other fields. The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared.

What is the difference between a class enum and a regular enum?

An enum can, just like a class , have attributes and methods. The only difference is that enum constants are public , static and final (unchangeable - cannot be overridden). An enum cannot be used to create objects, and it cannot extend other classes (but it can implement interfaces).

Can we have enum inside enum in C?

It is not possible to have enum of enums, but you could represent your data by having the type and cause separately either as part of a struct or allocating certain bits for each of the fields.

Can enum be defined inside a class C++?

Although enumerations are probably the most common type that is nested inside a class, C++ will let you define other types within a class, such as typedefs, type aliases, and even other classes!


2 Answers

No, for the reasons you give.

But I don't see why you're so hung up on making this a member function. Enum or no enum, I don't see the value in making it a member anyway. It should be a free function in the same enclosing namespace.

Let ADL handle the name lookup for you. What's wrong with this?

Color comp{complement(Color::RED)};
like image 98
Lightness Races in Orbit Avatar answered Oct 06 '22 04:10

Lightness Races in Orbit


It isn't exactly what you're asking for, but you could overload an operator for the enum class, and use that to complement it.

enum class Color { 
  RED,
  ORANGE,
  YELLOW,
  GREEN,
  CYAN,
  AZURE,
  BLUE,
  MAGENTA
};

Color operator~(Color c) {

  switch(c) {

    case Color::RED:     return Color::CYAN;
    case Color::ORANGE:  return Color::AZURE;
    case Color::YELLOW:  return Color::BLUE;
    case Color::GREEN:   return Color::MAGENTA;
    case Color::CYAN:    return Color::RED;
    case Color::AZURE:   return Color::ORANGE;
    case Color::BLUE:    return Color::YELLOW;
    case Color::MAGENTA: return Color::GREEN;

  }
}

~Color::RED == Color::CYAN
etc...
like image 29
Jason Avatar answered Oct 06 '22 03:10

Jason