Developer

C++ Tip: Simplify your coding with user-friendly enumerations

In programming, enumerations allow you to define a type composed of a predefined set of values. With this technique, you can improve your coding using a code-completion feature.

Enumerations are a great idiom. They allow you to define a type that is composed of a predefined set of values. The code becomes easier to write, and test, is more readable, and is easier to maintain—benefits you're likely to love. For example, check out the listing below; by reading the code, you'll instantly understand that the first working day is Monday:

enum week_day {
    Mon, Tue, Wed, Thu, Fri, Sat, Sun
};


week_day first_work_day;
first_work_day = Mon;

However, programmers need to deal with large amounts of code, in the order of hundreds of thousands to millions of lines. Therefore, it's very easy for you to forget names (of functions, classes, namespaces, etc). Code-completion is a great tool to help programmers deal with the plethora of names in current code—a feature most IDEs implement in some fashion.

Code-completion

Code-completion helps programmers by showing them possible ways to complete instruction(s). Type a few letters, and the environment suggests one or more possibilities to complete the current instruction, similar to what is shown in Figure A.

Figure A

A typical code-completion

The problem with code-completion is that it does not work for enumerations. More to the point, when dealing with an enumerated type, how do you know what set of values it's composed of? You would like something similar to Figure B.

Figure B

Enumerated completion

Unfortunately, this does not happen in any IDE I know of at this time, and it's very unlikely it will happen anytime soon. The good news is that you can get pretty close to that using the following technique.

Namespaces vs. structures


In order to allow code-completion, simply surround your enumeration in a namespace or a struct. You'll name the structure/namespace as your enumeration, and give your enumeration a new name (the simplest would be to call it type). An example is shown in Figure C.

Figure C

Namespace/struct

It's that simple! Your fellow programmers and those using or enhancing your code will certainly thank you for it. And the code will be even more readable—every usage of your enumeration will be prefixed by its type—as shown here:

// somewhere, in a distant header
namespace show {
    enum type {
        normal, hide, maximize, minimize, restore
    };
};

struct window {
    void show( ::show::type s);
    // ...
};

int main() {
    window w;
    // hide the window
    w.show(show::hide);

    // maximize the window
    w.show(show::maximize);
}

An even better benefit is when you have combination enumerations: where a valid value could be a combination of states, as you see in Figure D. By reading the code, you can clearly tell that checked, enabled, and focused are possible states of a check-box.

Figure D

You implement this technique using either a namespace (as I've shown you in the previous examples), or by using a structure; both have pros and cons. The advantages of namespaces include:

  • A namespace is open; you can add other new types/definitions to it
  • When using a namespace, no unneeded code is generated (when using a struct, some poor compilers might mistakenly generate the class's default constructor, etc., even though they're never needed)
  • They specify your intent in a more clear way: a namespace, as its name suggests, is a place where you collect names; a structure, on the other hand, is a collection of data. Thus, using a struct like shown above might be misleading to some programmers.

The drawbacks of namespaces include:

  • They cannot be used inside a class
  • You cannot inherit a namespace, like you can inherit a structure

In the light of the above, I recommend you use namespaces where possible, and structures where you must.

When you want to make an enumeration part of a class, you'll implement something like this code:

struct check_box {
    // CANNOT use a namespace here
    struct state {
        enum type {
            checked = 1, enabled = 2, focused = 4, pressed = 8
        };
    };
    void set_state(int s);
    // ...
};


int main() {
    check_box c;
    c.set_state(check_box::state::checked |
check_box::state::enabled); }

The latter case is quite advanced and somewhat rare. It occurs when you want to conceptually extend an enumeration, adding one or more values to it. For example, you might want to add a new check-box state: hot-tracked. Thus, you will extend the check_box class, and the state enumeration as shown in Figure E.

Figure E

Extend the enumeration

Friendly enumerations

Enumerations are a very useful C++ construct. Using the technique I've shown you, you can make them easier to use, read, and maintain. In a word: friendlier.

Editor's Picks

Free Newsletters, In your Inbox