HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

"EnumSpace" - enum inheritance attempt using namespace macro

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
enumspaceenumattemptinheritanceusingmacronamespace

Problem

EnumSpace

This file enables the use of a utility I like to call "EnumSpace". This utility is enums and namespaces combined together in order to create an entity that acts like an enum that is able to inherit and extend an already existing one.

It provides three macros for that purpose:

  • ENUMSPACE_CREATE



  • ENUMSPACE_EXTEND



  • ENUMSPACE_END



ENUMSPACE_CREATE should be used to create a new, independent EnumSpace. It receives the name you would like to give your EnumSpace as an argument.

ENUMSPACE_EXTEND should be used to extend an already existing EnumSpace. It receives two arguments:

  • The name of the EnumSpace you would like to inherit.



  • The name of the new EnumSpace.



ENUMSPACE_END should be used like a closing bracket to each of the above.

Usage example:

#include ".../enumspace.hpp"

ENUMSPACE_CREATE( First )         ONE                 ENUMSPACE_END
ENUMSPACE_EXTEND( First, Second ) TWO,   THREE, FOUR  ENUMSPACE_END
ENUMSPACE_EXTEND( Second, Third ) FIVE,  SIX,   SEVEN ENUMSPACE_END
ENUMSPACE_EXTEND( Third, Fourth ) EIGHT, NINE,  TEN   ENUMSPACE_END

int main()
{
std::cout
<< Fourth::ONE
<< Fourth::TWO
<< Fourth::THREE
<< Fourth::FOUR
<< Fourth::FIVE
<< Fourth::SIX
<< Fourth::SEVEN
<< Fourth::EIGHT
<< Fourth::NINE
<< Fourth::TEN;
}


Output:

0 2 3 4 6 7 8 10 11 12


You probably noticed the inconsistency. The ability to stitch EnumSpaces comes with a price: it is impossible to retain a straight streak of numbers automatically.

[ONE = 0, _last( = 1)]
[_first = _last = 1, 2, 3, 4, _last( = 5)]
[_first = _last = 5, 6, 7, 8, _last( = 9)]
[_first = _last = 9, 10, 11, 12, _last( = 13)]


You CAN manually declare the first element you add to be "first" (-> the previous inherited namespaces "last"):

``
ENUMSPACE_CREATE( First ) ONE ENUMSPACE_END
ENUMSPACE_EXTEND( First, Second ) TWO = _first, THREE, FOUR ENUMSPACE_END
ENUMSPACE_EXTEND( Second, Third ) FIVE = _first, S

Solution

You have already identified that it's inconvenient for users to have a gap in their values. That's easily remedied by starting the values immediately after the inherited ones:

_first = EnumSpace::_last - 1


A more convenient set of macros would use a variadic argument list to splice the values into the enum, no longer dependent on the user remembering ENUMSPACE_END, and always automatically balanced:

#define ENUMSPACE_CREATE(EnumSpaceName, ...)    \
    namespace EnumSpaceName {                   \
        enum {                                  \
            __VA_ARGS__,                        \
            _last                               \
        };                                      \
    }

#define ENUMSPACE_EXTEND(BaseSpace, NewSpace, ...)      \
    namespace NewSpace {                                \
        using namespace BaseSpace;                      \
        enum {                                          \
            _first = BaseSpace::_last - 1,              \
            __VA_ARGS__,                                \
            _last                                       \
        };                                              \
    }


I think this looks neater where it's used (and it makes Emacs indentation happier than the bare unbraced lists):

ENUMSPACE_CREATE(First, ONE)
ENUMSPACE_EXTEND(First, Second, TWO, THREE, FOUR)
ENUMSPACE_EXTEND(Second, Third, FIVE, SIX, SEVEN)
ENUMSPACE_EXTEND(Third, Fourth, EIGHT, NINE, TEN)

#include 
#include 
#include 
#include 

int main()
{
    using namespace Fourth;
    std::ranges::copy(std::array{
            ONE, TWO, THREE, FOUR, FIVE,
            SIX, SEVEN, EIGHT, NINE, TEN
        },
        std::ostream_iterator(std::cout, ", "));
}


0, 1, 2, 3, 4, 5, 6, 7, 8, 9,


One defect that this improved version doesn't address is that we can't specify the integer type underlying the enum, nor use enum class, with these declarations.

Code Snippets

_first = EnumSpace::_last - 1
#define ENUMSPACE_CREATE(EnumSpaceName, ...)    \
    namespace EnumSpaceName {                   \
        enum {                                  \
            __VA_ARGS__,                        \
            _last                               \
        };                                      \
    }

#define ENUMSPACE_EXTEND(BaseSpace, NewSpace, ...)      \
    namespace NewSpace {                                \
        using namespace BaseSpace;                      \
        enum {                                          \
            _first = BaseSpace::_last - 1,              \
            __VA_ARGS__,                                \
            _last                                       \
        };                                              \
    }
ENUMSPACE_CREATE(First, ONE)
ENUMSPACE_EXTEND(First, Second, TWO, THREE, FOUR)
ENUMSPACE_EXTEND(Second, Third, FIVE, SIX, SEVEN)
ENUMSPACE_EXTEND(Third, Fourth, EIGHT, NINE, TEN)

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>

int main()
{
    using namespace Fourth;
    std::ranges::copy(std::array<int, Fourth::_last>{
            ONE, TWO, THREE, FOUR, FIVE,
            SIX, SEVEN, EIGHT, NINE, TEN
        },
        std::ostream_iterator<int>(std::cout, ", "));
}

Context

StackExchange Code Review Q#106766, answer score: 3

Revisions (0)

No revisions yet.