BlackMATov b370676765 Happy New Year 🥳
2020-03-03 00:50:14 +07:00
2020-03-03 00:50:14 +07:00
2020-03-03 00:50:14 +07:00
2020-03-03 00:50:14 +07:00
2019-11-27 02:19:41 +07:00
2019-11-20 20:15:27 +07:00
2019-11-20 20:15:27 +07:00
2019-11-27 02:19:41 +07:00
2019-11-21 03:55:11 +07:00
2020-03-03 00:50:14 +07:00
2019-11-22 11:03:31 +07:00

enum.hpp

travis appveyor codecov language license paypal

Requirements

Installation

enum.hpp is a header-only library. All you need to do is copy the headers files from headers directory into your project and include them:

#include "enum.hpp/enum.hpp"

Also, you can add the root repository directory to your cmake project:

add_subdirectory(external/enum.hpp)
target_link_libraries(your_project_target enum.hpp)

Examples

Declarations

ENUM_HPP_DECL(debug_level, int,
    (level_info)
    (level_warning)
    (level_error))

// equivalent to:

enum debug_level : int {
    level_info,
    level_warning,
    level_error,
};

struct debug_level_traits {
    /*...*/
};
ENUM_HPP_CLASS_DECL(color, unsigned,
    (red = 1 << 0)
    (green = 1 << 1)
    (blue = 1 << 2)
    (white = red | green | blue))

// equivalent to:

enum class color : unsigned {
    red = 1 << 0,
    green = 1 << 1,
    blue = 1 << 2,
    white = red | green | blue,
};

struct color_traits {
    /*...*/
};

Traits using

namespace
{
    ENUM_HPP_CLASS_DECL(color, unsigned,
        (red = 0xFF0000)
        (green = 0x00FF00)
        (blue = 0x0000FF)
        (white = red | green | blue))
}

int main() {
    // size
    static_assert(color_traits::size == 4);

    // to_underlying
    static_assert(color_traits::to_underlying(color::white) == 0xFFFFFF);

    // to_string
    static_assert(color_traits::to_string(color::red) == "red");
    static_assert(color_traits::to_string(color(42)) == std::nullopt);

    // from_string
    static_assert(color_traits::from_string("green") == color::green);
    static_assert(color_traits::from_string("error") == std::nullopt);

    // to_index
    static_assert(color_traits::to_index(color::blue) == 2);
    static_assert(color_traits::to_index(color(42)) == std::nullopt);

    // from_index
    static_assert(color_traits::from_index(2) == color::blue);
    static_assert(color_traits::from_index(42) == std::nullopt);

    // names
    for ( auto n : color_traits::names ) {
        std::cout << n << ",";
    } // stdout: red,green,blue,

    return 0;
}

Generic context

namespace some_namespace
{
    ENUM_HPP_CLASS_DECL(color, unsigned,
        (red = 0xFF0000)
        (green = 0x00FF00)
        (blue = 0x0000FF)
        (white = red | green | blue))
}

// register traits in global namespace to generic access
ENUM_HPP_REGISTER_TRAITS(color)

int main() {
    using color = some_namespace::color;

    // to string
    static_assert(enum_hpp::to_string(color::red) == "red");

    // from string
    static_assert(enum_hpp::from_string<color>("red") == color::red);

    return 0;
}

Adapting external enums

namespace external_ns
{
    enum class external_enum : unsigned short {
        a = 10,
        b,
        c = a + b
    };

    // should be in the same namespace
    ENUM_HPP_TRAITS_DECL(external_enum,
        (a)
        (b)
        (c))
}

ENUM_HPP_REGISTER_TRAITS(external_ns::external_enum)

int main() {
    using ee = external_ns::external_enum;
    static_assert(enum_hpp::to_string(ee::a) == "a");
    static_assert(enum_hpp::from_string<ee>("c") == ee::c);
    return 0;
}

API

Enum traits

// declare enum
ENUM_HPP_DECL(
    /*enum_name*/,
    /*underlying_type*/,
    /*fields*/)

// declare enum class
ENUM_HPP_CLASS_DECL(
    /*enum_name*/,
    /*underlying_type*/,
    /*fields*/)

// declare only traits
ENUM_HPP_TRAITS_DECL(
    /*enum_name*/,
    /*fields*/)

struct /*enum_name*/_traits {
    using underlying_type = /*underlying_type*/;
    static constexpr std::size_t size = /*field_count*/;

    static constexpr const std::array</*enum_name*/, /*field_count*/ > values = {
        /*enum values*/
    };

    static constexpr const std::array<std::string_view, /*field_count*/> names = {
        /*enum names*/
    };

    static constexpr /*underlying_type*/ to_underlying(/*enum_name*/ e) noexcept;

    static constexpr std::optional<std::string_view> to_string(/*enum_name*/ e) noexcept;
    static constexpr std::string_view to_string_or_empty(/*enum_name*/ e) noexcept;
    static std::string_view to_string_or_throw(/*enum_name*/ e);

    static constexpr std::optional</*enum_name*/> from_string(std::string_view name) noexcept;
    static constexpr /*enum_name*/ from_string_or_default(std::string_view name, /*enum_name*/ def) noexcept;
    static /*enum_name*/ from_string_or_throw(std::string_view name);

    static constexpr std::optional<std::size_t> to_index(/*enum_name*/ e) noexcept;
    static constexpr std::size_t to_index_or_invalid(/*enum_name*/ e) noexcept;
    static std::size_t to_index_or_throw(/*enum_name*/ e);

    static constexpr std::optional</*enum_name*/> from_index(std::size_t index) noexcept;
    static constexpr /*enum_name*/ from_index_or_default(std::size_t index, /*enum_name*/ def) noexcept;
    static /*enum_name*/ from_index_or_throw(std::size_t index);
};

Generic functions

// should be in global namespace
ENUM_HPP_REGISTER_TRAITS(/*declared_enum_name*/)

namespace enum_hpp
{
    template < typename Enum >
    using traits_t = typename traits<Enum>::type;

    template < typename Enum >
    using underlying_type = typename traits_t<Enum>::underlying_type;

    template < typename Enum >
    constexpr std::size_t size() noexcept;

    template < typename Enum >
    constexpr const std::array<Enum, size<Enum>()>& values() noexcept;

    template < typename Enum >
    constexpr const std::array<std::string_view, size<Enum>()>& names() noexcept;

    template < typename Enum >
    constexpr typename traits_t<Enum>::underlying_type to_underlying(Enum e) noexcept;

    template < typename Enum >
    constexpr std::optional<std::string_view> to_string(Enum e) noexcept;

    template < typename Enum >
    constexpr std::string_view to_string_or_empty(Enum e) noexcept;

    template < typename Enum >
    std::string_view to_string_or_throw(Enum e);

    template < typename Enum >
    constexpr std::optional<Enum> from_string(std::string_view name) noexcept;

    template < typename Enum >
    constexpr Enum from_string_or_default(std::string_view name, Enum def) noexcept;

    template < typename Enum >
    Enum from_string_or_throw(std::string_view name);

    template < typename Enum >
    constexpr std::optional<std::size_t> to_index(Enum e) noexcept;

    template < typename Enum >
    constexpr std::size_t to_index_or_invalid(Enum e) noexcept;

    template < typename Enum >
    std::size_t to_index_or_throw(Enum e);

    template < typename Enum >
    constexpr std::optional<Enum> from_index(std::size_t index) noexcept;

    template < typename Enum >
    constexpr Enum from_index_or_default(std::size_t index, Enum def) noexcept;

    template < typename Enum >
    Enum from_index_or_throw(std::size_t index);
}

Alternatives

Better Enums

  • Low variadic macros limit (64)
  • Replaces C++ enum semantics to custom class

wise_enum

Magic Enum

  • Amazing but requires at least GCC 9.0

License (MIT)

Languages
C++ 96.1%
CMake 3.9%