У меня есть несколько типов перечислений в некоторых файлах заголовков библиотек, которые я использую, и я хочу иметь способ преобразования значений перечисления в пользовательские строки - и наоборот.
RTTI не сделает этого за меня, потому что «пользовательские строки» должны быть немного более читаемыми, чем перечисления.
Решением грубой силы было бы множество подобных функций, но я считаю, что это слишком похоже на C.
enum MyEnum {VAL1, VAL2,VAL3};
String getStringFromEnum(MyEnum e)
{
switch e
{
case VAL1: return "Value 1";
case VAL2: return "Value 2";
case VAL1: return "Value 3";
default: throw Exception("Bad MyEnum");
}
}
У меня интуиция есть ощущение, что есть элегантное решение с использованием шаблонов, но я пока не могу осмыслить его.
ОБНОВЛЕНИЕ: спасибо за предложения - я должен был прояснить, что перечисления определены в заголовке сторонней библиотеки, поэтому я не хочу менять их определение.
Сейчас я чувствую, что избегаю шаблонов и делаю что-то вроде этого:
char * MyGetValue(int v, char *tmp); // implementation is trivial
#define ENUM_MAP(type, strings) char * getStringValue(const type &T) \
{ \
return MyGetValue((int)T, strings); \
}
; enum eee {AA,BB,CC}; - exists in library header file
; enum fff {DD,GG,HH};
ENUM_MAP(eee,"AA|BB|CC")
ENUM_MAP(fff,"DD|GG|HH")
// To use...
eee e;
fff f;
std::cout<< getStringValue(e);
std::cout<< getStringValue(f);
Ответы:
Если вы хотите, чтобы перечисления назывались строками, см. Этот пост . В противном случае
std::map<MyEnum, char const*>
подойдет a . (Нет смысла копировать строковые литералы в std :: strings на карте)Для дополнительного синтаксического сахара вот как написать класс map_init. Цель - позволить
Функция
template <typename T> map_init(T&)
возвращаетmap_init_helper<T>
.map_init_helper<T>
хранит T & и определяет тривиальныйmap_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Возврат*this
изoperator()
разрешает цепочкуoperator()
, какoperator<<
вstd::ostream
s)Поскольку функция и вспомогательный класс являются шаблонными, вы можете использовать их для любой карты или структуры, подобной карте. Т.е. он также может добавлять записи в
std::unordered_map
Если вам не нравится писать эти помощники, boost :: assign предлагает ту же функциональность из коробки.
источник
Решение MSalters хорошее, но в основном его реализуют заново
boost::assign::map_list_of
. Если у вас есть ускорение, вы можете использовать его напрямую:источник
eee
в вашем случае.error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
.Автоматически создавать одну форму из другой.
Источник:
Сформирован:
Если значения перечисления велики, то сгенерированная форма может использовать unordered_map <> или шаблоны, как предлагает Константин.
Источник:
Сформирован:
Пример:
источник
Я помню, как ответил на этот вопрос в другом месте на StackOverflow. Повторение здесь. По сути, это решение, основанное на вариативных макросах, и его довольно легко использовать:
Чтобы использовать его в своем коде, просто выполните:
источник
Я предлагаю сочетание использования X-макросов - лучшее решение и следующих функций шаблона:
Взять в долг у marcinkoziukmyopenidcom и продлить
colour.def
источник
Я использую это решение, которое воспроизвожу ниже:
источник
Если вы хотите получить строковое представление
MyEnum
переменных , шаблоны не подойдут. Шаблон может быть специализирован на целых значениях, известных во время компиляции.Однако, если вы этого хотите, попробуйте:
Это многословно, но будет обнаружены ошибки, подобные той, которую вы сделали в вопросе - ваш
case VAL1
дублируется.источник
Я потратил больше времени на изучение этой темы, что хотел бы признать. К счастью, в мире есть отличные решения с открытым исходным кодом.
Это два отличных подхода, пусть и недостаточно хорошо известных (пока).
wise_enum
Лучше перечисления
источник
У меня возникнет соблазн иметь карту m - и встроить ее в перечисление.
настройка с помощью m [MyEnum.VAL1] = "Значение 1";
и все сделано.
источник
Мне эта функция требовалась несколько раз для отладки / анализа кода других пользователей. Для этого я написал сценарий Perl, который генерирует класс с несколькими перегруженными
toString
методами. КаждыйtoString
метод принимаетEnum
в качестве аргумента и возвращаетconst char*
.Конечно, сценарий не разбирает C ++ на предмет перечислений, но использует теги ctags для создания таблицы символов.
Скрипт Perl находится здесь: http://heinitz-it.de/download/enum2string/enum2string.pl.html
источник
Ваши ответы вдохновили меня написать несколько макросов самостоятельно. Мои требования были следующие:
записывать каждое значение перечисления только один раз, поэтому нет двойных списков для поддержки
не храните значения перечисления в отдельном файле, который позже #included, поэтому я могу записать его где захочу
не заменяйте само перечисление, я все еще хочу, чтобы был определен тип перечисления, но в дополнение к нему я хочу иметь возможность сопоставить каждое имя перечисления с соответствующей строкой (чтобы не влиять на устаревший код)
поиск должен быть быстрым, поэтому желательно без переключателя для этих огромных перечислений
Этот код создает классическое перечисление с некоторыми значениями. Кроме того, он создает как std :: map, который сопоставляет каждое значение перечисления с его именем (например, map [E_SUNDAY] = "E_SUNDAY" и т. Д.)
Хорошо, вот код:
EnumUtilsImpl.h :
EnumUtils.h // это файл, который вы хотите включить всякий раз, когда вам нужно сделать это, вы будете использовать макросы из него:
MyProjectCodeFile.h // это пример того, как использовать его для создания настраиваемого перечисления:
Приветствия.
источник
Вот попытка автоматически получить операторы потока << и >> в enum с помощью только однострочной макрос-команды ...
Определения:
Использование:
Не уверен в ограничениях этой схемы ... комментарии приветствуются!
источник
в шапке:
в файле .cpp:
Предостережение: не обрабатывайте неверный индекс массива. :) Но вы можете легко добавить функцию для проверки перечисления перед получением строки из массива.
источник
Я просто хотел показать это возможное элегантное решение с помощью макросов. Это не решает проблему, но я думаю, что это хороший способ переосмыслить проблему.
---- РЕДАКТИРОВАТЬ ----
После некоторых интернет-исследований и некоторых собственных опытов я пришел к следующему решению:
Я просто хотел опубликовать это, возможно, кто-то найдет это решение полезным. Нет необходимости в классах шаблонов, нет необходимости в C ++ 11 и нет необходимости в повышении, поэтому это также можно использовать для простого C.
---- РЕДАКТИРОВАТЬ2 ----
информационная таблица может вызвать некоторые проблемы при использовании более двух перечислений (проблема компилятора). Следующее обходное решение помогло:
источник
Выше мое простое решение. Одним из преимуществ этого является «ЧИСЛО», которое контролирует размер массива сообщений, а также предотвращает доступ за пределы границ (если вы используете его с умом).
Вы также можете определить функцию для получения строки:
В дополнение к моему решению я нашел весьма интересным следующее. Это в целом решило проблему синхронизации вышеупомянутой.
Слайды здесь: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724
Код здесь: https://github.com/arunksaha/enum_to_string
источник
Я знаю, что опаздываю на вечеринку, но для всех, кто заходит на эту страницу, вы могли бы попробовать это, это проще, чем все там, и имеет больше смысла:
источник
Недавно у меня была такая же проблема с библиотекой поставщиков (Fincad). К счастью, поставщик предоставил XML-документацию для всех перечислений. В итоге я создал карту для каждого типа перечисления и предоставил функцию поиска для каждого перечисления. Этот метод также позволяет вам перехватить поиск за пределами диапазона перечисления.
Я уверен, что swig может сделать что-то подобное для вас, но я рад предоставить утилиты для генерации кода, написанные на ruby.
Вот пример кода:
Похоже, вы хотите пойти другим путем (enum to string, а не string to enum), но это должно быть тривиально для обратного.
-Whit
источник
Посмотрите, подходит ли вам следующий синтаксис:
Если да, то вы можете прочитать эту статью:
http://www.gamedev.net/reference/snippets/features/cppstringizing/
источник
этот правильный старый беспорядок - мои усилия, основанные на фрагментах из SO. Для поддержки более 20 значений перечисления необходимо расширить for_each. Протестировал на visual studio 2019, clang и gcc. C ++ 11
который производит следующий код
Жаль, что вам придется прыгнуть с препроцессором, чтобы сделать это на одном из самых используемых языков программирования в мире ...
источник
Используя назначенные инициализаторы массива, ваш строковый массив не зависит от порядка элементов в перечислении:
источник