Комментарии 23
Variadic templates не пробовали?
+11
Пробовал не получилось к сожалению, если есть идея как это сделать без макросов буду очень признателен за подсказку.
0
Если я понял верно Вашу задачу, то может быть как-то так:
//твое перечисление
enum class MyEnum
{
One,
Two,
Three
//etc
};
//соответствующие перечислению строки
char OneStr[] = "One";
char TwoStr[] = "Two";
char ThreeStr[] = "Three";
//etc
template <typename T, T t>
struct ValueToType {}; //смотри Александреску
template <MyEnum ParamEnum, typename Param, Param Val>
class MyPair
{
public:
//опять же, по поводу параметров этих функций, смотри Александреску
MyEnum toEnum(ValueToType<Param, Val> const&) { return ParamEnum; }
Param toParam(ValueToType<MyEnum, ParamEnum> const&) { return Val; }
};
template <class ... T>
class MyEnumDecoder {}; //базовый шаблон, который мы "раскрутим" специализацией
template <MyEnum ParamEnum, typename Param, Param Val, class ... T>
class MyEnumDecoder<MyPair<ParamEnum, Param, Val>, T ...> :
protected MyPair<ParamEnum, Param, Val>, protected MyEnumDecoder<T ...>
{
private:
using MyPair<ParamEnum, Param, Val>::toEnum;
using MyPair<ParamEnum, Param, Val>::toParam;
using MyEnumDecoder<T ...>::toEnum;
using MyEnumDecoder<T ...>::toParam;
public:
MyEnumDecoder(MyPair<ParamEnum, Param, Val> mp, T ... others) :
MyPair<ParamEnum, Param, Val>(mp), MyEnumDecoder<T ...>(others ...) {}
template <Param param>
MyEnum toEnum()
{
return this->toEnum(ValueToType<Param, param>());
}
template <MyEnum paramEnum>
Param toParam()
{
return this->toParam(ValueToType<MyEnum, paramEnum>());
}
};
//это замыкание рекурсии. чтобы понять, что происходит выше, смотри что происходит тут
template <MyEnum ParamEnum, typename Param, Param Val>
class MyEnumDecoder<MyPair<ParamEnum, Param, Val>> :
protected MyPair<ParamEnum, Param, Val>
{
private:
using MyPair<ParamEnum, Param, Val>::toEnum;
using MyPair<ParamEnum, Param, Val>::toParam;
public:
MyEnumDecoder(MyPair<ParamEnum, Param, Val> mp) :
MyPair<ParamEnum, Param, Val>(mp) {}
template <Param param>
MyEnum toEnum()
{
return this->toEnum(ValueToType<Param, param>());
}
template <MyEnum paramEnum>
Param toParam()
{
return this->toParam(ValueToType<MyEnum, paramEnum>());
}
};
/*************************************************************************************/
int _tmain(int argc, _TCHAR* argv[])
{
MyPair<MyEnum::One, char*, OneStr> mpOne;
MyPair<MyEnum::Two, char*, TwoStr> mpTwo;
MyPair<MyEnum::Three, char*, ThreeStr> mpThree;
MyEnumDecoder<
MyPair<MyEnum::One, char*, OneStr>,
MyPair<MyEnum::Two, char*, TwoStr>,
MyPair<MyEnum::Three, char*, ThreeStr>
> mp(mpOne, mpTwo, mpThree);
MyEnum me = mp.toEnum<OneStr>();
char* str = mp.toParam<MyEnum::Three>();
getchar();
return 0;
}
0
идея конечно в целом хорошая но чтобы сделать запись компактной все равно придется оборачивать ее в макросы
и к тому же
не компилируется а мне это не подходит, потому как именно эту строку я считываю из конфига, на этапе компиляции она как раз не известна.
и к тому же
const char* value = "one";
MyEnum me = mp.toEnum<value>();
char* str = mp.toParam<me>();
не компилируется а мне это не подходит, потому как именно эту строку я считываю из конфига, на этапе компиляции она как раз не известна.
0
Теперь ясно. Значит можно упростить и сделать проверку
char* str = mp.toParam<me>();
еще на этапе компиляции, а MyEnum me = mp.toEnum<value>();
будет всегда рантайм проверка.0
char* str = mp.toParam<me>();
тоже не компилируется
все параметры шаблонов должны быть известны еще на этапе компиляции
а у меня преобразования могут быть и в ту, и в другую строну в рантайме
0
Да, Вы правы. Я подразумевал, что у Вас в коде стоит преобразование в духе:
А так, действительно, вся карта отображения двух множеств будет только в рантайме.
char* str = mp.toParam<MyEnum::One>();
А так, действительно, вся карта отображения двух множеств будет только в рантайме.
0
единственная возможность оптимизации это ф-я tolower но на макросах этого сделать я не смог а constexpr не поддерживает даже 2013 MSVC(только November 2013 CTP of the Visual C++ Compiler)
к тому же всетаки поиск по map сравним по скорости даже с преобразованием строки в число, поэтому скорость парсинга конфигов почти такая же как с цифрами.
к тому же всетаки поиск по map сравним по скорости даже с преобразованием строки в число, поэтому скорость парсинга конфигов почти такая же как с цифрами.
0
Я решил подобную ситуацию инным способом. С помощью std::tuple.
Затем
tuple_get_tag — ф-ия которая фозвращает TagValue::value для заданого tag (compile-time, аналог std::get<> ).
Получается что то вроде compile-time hash-map.
P.S. если значения константные и типа int, можно либо использовать std::integral_constant, либо сделать структуру TagInt, аналогичную TagValue. (в обоих случаях будет полный compile-time).
template<class Tag, class Type>
struct TagValue{
using tag = Tag;
using type = Type;
Type value;
TagValue(Type &value) : value(value){}
TagValue(Type &&value) : value(forward<Type>(value) ){}
};
template<class Tag, class Type>
using tv = TagValue<Tag, Type>; // сокращенная запись
// type autodetect
/// call this to auto deduce &/&&
template<typename _tag, typename T>
TagValue<_tag, T> mtv(T &&value){
return TagValue<_tag, T>( std::forward<T>(value) );
}
Затем
namespace tags{
class three;
}
using namespace tags;
auto list = make_tuple(
tv<class one, int>(1) ,
mtv<class two>(2), // либо
mtv<three>(3) // либо (если class three уже используется, можно не объявлять в namespace tags)
)
int num2 = tuple_get_tag<class two>(list);
int num3 = tuple_get_tag<three>(list);
tuple_get_tag — ф-ия которая фозвращает TagValue::value для заданого tag (compile-time, аналог std::get<> ).
Получается что то вроде compile-time hash-map.
P.S. если значения константные и типа int, можно либо использовать std::integral_constant, либо сделать структуру TagInt, аналогичную TagValue. (в обоих случаях будет полный compile-time).
+3
В Qt enum определённый в QObject классе можно преобразовывать к строке и обратно.
+1
С одной стороны, хочется читаемых конфигов, с другой — быстрого парсинга и быстрого обращения по этому типу.
Глядя на всё то, что вы понаписали после этой фразы, очень хочется спросить: для чего вам этого хочется? Нужны очень весомые основания, чтобы встраивать в свой проект такую жуть.
Было бы здорово, если бы вы привели пример, когда действительно жизненно необходимо использовать перечисления, вместо хешей.
+8
Плюсы решения
1 — простота синтаксиса (синтаксис похож на обычным enum)
2 — минимум кода (столько же сколько объявить обычный enum)
3 — возможность сделать итерироваться по значениям enum
4 — скорость работы (при мапе из 20 элементов скорость поиска в 6 раз выше чем std::map<string,int> и в 3.5 раза std::unordered_map<std::string,int>)
5 — отсутствие зависимостей(кроме std::string std::map)
6 — возможность использовать switch (что тоже положительно сказывается на скорости)
7 — возможность приведения имен строк к нижнему регистру STRING_ENUM( MyStringEnum, ONE, TWO, THREE); в строку будет преобразовано как «one», «two», «three»
8 — типобезопасность
Минусы
1 — Шаблонная магия
2 — 32 элемента максимум
пример относительно скорости ideone.com/1HNGIe
1 — простота синтаксиса (синтаксис похож на обычным enum)
2 — минимум кода (столько же сколько объявить обычный enum)
3 — возможность сделать итерироваться по значениям enum
4 — скорость работы (при мапе из 20 элементов скорость поиска в 6 раз выше чем std::map<string,int> и в 3.5 раза std::unordered_map<std::string,int>)
5 — отсутствие зависимостей(кроме std::string std::map)
6 — возможность использовать switch (что тоже положительно сказывается на скорости)
7 — возможность приведения имен строк к нижнему регистру STRING_ENUM( MyStringEnum, ONE, TWO, THREE); в строку будет преобразовано как «one», «two», «three»
8 — типобезопасность
Минусы
1 — Шаблонная магия
2 — 32 элемента максимум
пример относительно скорости ideone.com/1HNGIe
0
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
гейм девелопмент же. Там 80% всего — это конфиги
0
Открою страшный секрет: конфиги в геймдеве пишут люди и в основном для людей, и как раз читаемость первична. Если конфигов много и их загрузка занимает порядочное время, то их можно как то обрабатывать. Был у меня проект где весь мир был в конфигах ~ 15mb XML далее скриптами делалось 2 выгонки для сервер и для клиента. Далее еще по ним проходился другой скрипт и удалял все что можно(пробелы табы неиспользуемые поля и тд). Но если проект не столь масштабен то читаемость на первом месте.
+1
Забавный велосипед, но если нужна кросс-язычность, лучше protobuf enum — особенно когда протобуф уже есть в проекте.
+2
У предложенного подхода (на такого рода макросах) есть как минимум пара недостатков:
1. При большом размере перечисления компилятор начинает тупить на раскрытии всей этой макросни. А если компилятор и прожевывает, то начинает тупить IDE, которая тоже хочет всё это раскрыть в памяти.
2. Очевидно, поддерживаются перечисления, начинающиеся с 0 и нет возможности задания конкретного значения для элемента перечисления.
В своих собственных экспериментах я остановился в итоге на варианте, используемом также в llvm/clang'е, когда все такого рода enum'ы выносятся в отдельный .h-файл, поэлементно оборачиваются в макросы, а #define'ы перед включением этого .h-ника определяют то, что будет на выходе — определение enum'а, или сериализатор в строки.
1. При большом размере перечисления компилятор начинает тупить на раскрытии всей этой макросни. А если компилятор и прожевывает, то начинает тупить IDE, которая тоже хочет всё это раскрыть в памяти.
2. Очевидно, поддерживаются перечисления, начинающиеся с 0 и нет возможности задания конкретного значения для элемента перечисления.
В своих собственных экспериментах я остановился в итоге на варианте, используемом также в llvm/clang'е, когда все такого рода enum'ы выносятся в отдельный .h-файл, поэлементно оборачиваются в макросы, а #define'ы перед включением этого .h-ника определяют то, что будет на выходе — определение enum'а, или сериализатор в строки.
0
Добрый день, newnon!
Меня тоже очень интересует данная тема. Прочитал Вашу статью в сентябре и решил вернуться к своему давнему желанию — сделать генератор Enum'ов. Если Вам интересно, вот сегодня опубликовал.
Спасибо за мотивацию! :)
Меня тоже очень интересует данная тема. Прочитал Вашу статью в сентябре и решил вернуться к своему давнему желанию — сделать генератор Enum'ов. Если Вам интересно, вот сегодня опубликовал.
Спасибо за мотивацию! :)
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
String enum — строковые enum