I am using the following smart enum structure:
/* MySmartEnum.hpp */
#pragma once
#include <array>
template <class E>
static const auto& value_string_pairs();
#define MY_EXPAND(x) x
#define MY_ARRAY_PAIR(name, x) { #x, name::x }
#define MY_STR_CONCAT_(a, ...) a##__VA_ARGS__
#define MY_STR_CONCAT(a, ...) MY_STR_CONCAT_(a, __VA_ARGS__)
#define MY_ARG_COUNT_(_1,_2,_3,_4,VAL,...) VAL
#define MY_ARG_COUNT(...) MY_EXPAND(MY_ARG_COUNT_(__VA_ARGS__,4,3,2,1))
#define MY_LOOP_1(f, n, x) f(n,x)
#define MY_LOOP_2(f, n, x, ...) f(n,x) , MY_EXPAND(MY_LOOP_1(f, n, __VA_ARGS__))
#define MY_LOOP_3(f, n, x, ...) f(n,x) , MY_EXPAND(MY_LOOP_2(f, n, __VA_ARGS__))
#define MY_ENUM_IMPL(name, loop_func_name, ...) \
template<> inline const auto& value_string_pairs<name>() { \
using element_t = std::pair<const char*, name>; \
static const std::array<element_t, MY_ARG_COUNT(__VA_ARGS__)> values = { element_t \
MY_EXPAND(loop_func_name(MY_ARRAY_PAIR, name, __VA_ARGS__)) }; \
return values; }
#define MY_ENUM_CLASS(name, ...) enum class name { __VA_ARGS__ }; \
MY_ENUM_IMPL(name, MY_STR_CONCAT(MY_LOOP_, MY_ARG_COUNT(__VA_ARGS__)), __VA_ARGS__)
Then I maintain an additional file with all the enum types:
/* Enums.hpp */
#pragma once
#include "MySmartEnum.hpp"
MY_ENUM_CLASS(Timespan, Week, Month, Year)
MY_ENUM_CLASS(Interpolation, Linear, Cubic)
For example MY_ENUM_CLASS(Timespan, Week, Month, Year)
expands to
enum class Timespan { Week, Month, Year };
template<>
inline const auto& value_string_pairs<Timespan>() {
using element_t = std::pair<const char*, Timespan>;
static const std::array<element_t, 3> values = { element_t
{ "Week", Timespan::Week },
{ "Month", Timespan::Month },
{ "Year", Timespan::Year } };
return values;
}
So right now, everything is implemented in the header. But I want to move the implementation to an Enums.cpp
file. Firstly, I can easily change MY_ENUM_CLASS(...)
to only define the enum & function signature in Enums.hpp
:
#define MY_ENUM_CLASS(name, ...) enum class name { __VA_ARGS__ }; \
template<> const auto& value_string_pairs<name>();
But how do I move the implementation of value_string_pairs<Timespan>()
into Enums.cpp
, but without having to list all enum values again? Is there a way to #include "Enums.hpp"
in Enums.cpp
, un-define MY_ENUM_CLASS
and then re-define MY_ENUM_CLASS
inclusive of MY_ENUM_IMPL
such that MY_ENUM_CLASS(Timespan, Week, Month, Year)
expands to the full function implementation (but only in Enums.cpp
)?