Я не вижу "симпатичных" в ваших требованиях, поэтому я отправляю это решение, реализованное с использованием библиотеки препроцессора Boost.
Как предварительный отказ от ответственности, я не много использовал Boost.Preprocessor, и я только протестировал это с тестовыми примерами, представленными здесь, поэтому могут быть ошибки, и может быть более простой и понятный способ сделать это. Я, конечно, приветствую комментарии, исправления, предложения, оскорбления и т. Д.
Вот и мы:
#include <boost/preprocessor.hpp>
#define EXPAND_ENUM_VALUE(r, data, i, elem) \
BOOST_PP_SEQ_ELEM(0, elem) \
BOOST_PP_IIF( \
BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE(elem), 2), \
= BOOST_PP_SEQ_ELEM(1, elem), \
BOOST_PP_EMPTY()) \
BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(data, BOOST_PP_ADD(i, 1)))
#define ADD_CASE_FOR_ENUM_VALUE(r, data, elem) \
case BOOST_PP_SEQ_ELEM(0, elem) : break;
#define DEFINE_UNIQUE_ENUM(name, values) \
enum name \
{ \
BOOST_PP_SEQ_FOR_EACH_I(EXPAND_ENUM_VALUE, \
BOOST_PP_SEQ_SIZE(values), values) \
}; \
\
namespace detail \
{ \
void UniqueEnumSanityCheck##name() \
{ \
switch (name()) \
{ \
BOOST_PP_SEQ_FOR_EACH(ADD_CASE_FOR_ENUM_VALUE, name, values) \
} \
} \
}
Затем мы можем использовать его так:
DEFINE_UNIQUE_ENUM(DayOfWeek, ((Monday) (1))
((Tuesday) (2))
((Wednesday) )
((Thursday) (4)))
Значение перечислителя является необязательным; этот код генерирует перечисление, эквивалентное:
enum DayOfWeek
{
Monday = 1,
Tuesday = 2,
Wednesday,
Thursday = 4
};
Он также генерирует функцию проверки работоспособности, которая содержит оператор переключения, как описано в ответ Бена Фойгта . Если мы изменим объявление перечисления так, чтобы у нас были неуникальные значения перечислителя, например,
DEFINE_UNIQUE_ENUM(DayOfWeek, ((Monday) (1))
((Tuesday) (2))
((Wednesday) )
((Thursday) (1)))
не будет компилироваться (Visual C ++ сообщает об ожидаемой ошибке C2196: значение регистра '1' уже используется ).
Спасибо также Мэтью М., , чей ответ на другой вопрос заинтересовал меня библиотекой препроцессора Boost.