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

Smart enum templates

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

Problem

Here is some code I wrote 10 years ago. I'm now reviewing it and there are a lot of things I don't like.

There is possibility for weird behaviour if the template is attempted to be used with a type that I didn't intend. Also I don't like the big macros for DECLARE and DEFINE; and weird compile errors can occur if it is not used in just the right way.

Any suggestions are welcome; I do have C++11 access now (although I didn't when first writing this of course).

The goal of SmartEnum is to:

  • Provide a bijection (unique two-way mapping) between an enum type and a string.



  • Provide a bijection between each enum item and a string



  • Provide a description string for the enum.



  • Convert an enum value to an integral value



  • Convert an integral value to an enum value, throwing if no valid enum value exists. This must be the inverse of the previous conversion



The purpose I use SmartEnum for is that I read and write a configuration file in human-readable format, and in the file the enums are referred to by name; and the enum items can also be referred to by name. I include enums in this scheme via the following function:

// Convert to builtin and/or enum automatically!
template T to_any(std::string const &s)
{
// Blank string goes to zero. (Config2XML relies on this)
    long v = 0;
    if (!s.empty())
        v = to_integral_type(s, -1);   // does what it sounds like

#pragma option push -w-8008         // compiler complains about condition always false/true
#pragma option push -w-8066
    if (enum_properties::is_enum)
        return to_enum(v);
    else
        return static_cast(v);
#pragma option pop
#pragma option pop
}

// this is needed as the previous function barfs if instantiated with std::string
template<> inline std::string to_any(std::string const &s)
    { return s; }


The code for SmartEnum:

```
#ifndef H_SMART_ENUM
#define H_SMART_ENUM

#include
#include
#include
#include
//------------------------------------

Solution

Since you have access to a C++11 compiler, you should use the standard type trait std::is_enum in the default version of your template instead of just writing is_enum = false. Also, it should be constexpr:

template struct enum_properties
{
    static constexpr bool is_enum = std::is_enum::value;
    // ...
};


Now, you don't have any mean to know whether T is a simple enum or a "smart" one though. The name is_enum was confusing, and since there is already such a trait in the standard, your class should reflect its behaviour. Now, we want another mean to differenciate simple enums from smart ones. I propose to add another constant in enum_properties, along the lines of std::numeric_limits::is_specialized. This constant would tell whether enum_properties is specialized for a given type, and the name is less ambiguous than the previous one.

template struct enum_properties
{
    static constexpr bool is_enum = std::is_enum::value;
    static constexpr bool is_specialized = false;
    // ...
};

#define DECLARE_SMART_ENUM(E) \
    template<> struct enum_properties {  \
        static constexpr bool is_enum = std::is_enum::value; \
        static constexpr bool is_specialized = true; \
        /* ... */ \
    };

Code Snippets

template<typename T> struct enum_properties
{
    static constexpr bool is_enum = std::is_enum<T>::value;
    // ...
};
template<typename T> struct enum_properties
{
    static constexpr bool is_enum = std::is_enum<T>::value;
    static constexpr bool is_specialized = false;
    // ...
};

#define DECLARE_SMART_ENUM(E) \
    template<> struct enum_properties<E> {  \
        static constexpr bool is_enum = std::is_enum<E>::value; \
        static constexpr bool is_specialized = true; \
        /* ... */ \
    };

Context

StackExchange Code Review Q#54124, answer score: 7

Revisions (0)

No revisions yet.