boost::lexical_cast: из std::string в enum
От: emergenter Россия  
Дата: 10.11.15 19:37
Оценка:
Подскажите пожалуйста можно ли сделать преобразование из std::string в enum?

enum my_enum
{
    one,
    two,
    three
}


my_enum current;

current = boost::lexical_cast<my_enum>("one");


Как лучше делать такое преобразование?
Re: boost::lexical_cast: из std::string в enum
От: MTD https://github.com/mtrempoltsev
Дата: 10.11.15 23:21
Оценка: 9 (3)
Здравствуйте, emergenter, Вы писали:

E>Подскажите пожалуйста можно ли сделать преобразование из std::string в enum?


Чтобы работал lexical_cast так:

std::istream& operator>>(std::istream& stream, my_enum& value)
{
    std::string data;
    stream >> data;

    if (data == "one") value = one;
    else if (data == "two") value = two;
    else if (data == "three") value = three;
    else stream.setstate(std::ios::failbit);

    return stream;
}


Дополнительно, чтобы сериализовать значения тебе надо будет дописать std::ostream& operator>>(std::ostream& stream, my_enum value)
Re[2]: boost::lexical_cast: из std::string в enum
От: Went  
Дата: 11.11.15 06:02
Оценка:
Здравствуйте, MTD, Вы писали:
MTD>Чтобы работал lexical_cast так:
А оно "one 1" к one не преобразует?
Re[3]: boost::lexical_cast: из std::string в enum
От: MTD https://github.com/mtrempoltsev
Дата: 11.11.15 06:39
Оценка: 6 (1)
Здравствуйте, Went, Вы писали:

MTD>>Чтобы работал lexical_cast так:

W>А оно "one 1" к one не преобразует?

Нет, lexical_cast проверяет флаг eof и если что-то осталось в потоке, то полетит исключение.
Re[2]: boost::lexical_cast: из std::string в enum
От: Igore Россия  
Дата: 11.11.15 06:57
Оценка:
Здравствуйте, MTD, Вы писали:

MTD>Чтобы работал lexical_cast так:


MTD>std::istream& operator>>(std::istream& stream, my_enum& value)

А в чем отличие от такое кода и что лучше?

namespace boost{
template <> 
inline my_enum lexical_cast< my_enum, std::string >( const std::string& arg )
{
     my_enum result;

     if (arg == "one") result = one;
     else if (arg == "two") result = two;
     else if (arg == "three") result = three;
     else throw std::runtime_error( "..." );

     return result;
}
}// namespace boost
Отредактировано 11.11.2015 6:58 Igore . Предыдущая версия .
Re[3]: boost::lexical_cast: из std::string в enum
От: MTD https://github.com/mtrempoltsev
Дата: 12.11.15 04:29
Оценка: +1
Здравствуйте, Igore, Вы писали:

I>А в чем отличие от такое кода и что лучше?


Главное отличие — это не lexical_cast и соответсвенно поведение может отличаться. Что лучше? Ну твой вариант однозначно быстрее. Лично я бы не стал мудрить и просто написал бы рядом с объявлением me_enum функцию to_string(my_enum).
Re[4]: boost::lexical_cast: из std::string в enum
От: Igore Россия  
Дата: 12.11.15 06:26
Оценка:
Здравствуйте, MTD, Вы писали:

I>>А в чем отличие от такое кода и что лучше?

MTD>Главное отличие — это не lexical_cast и соответсвенно поведение может отличаться.
В смысле? Это просто специализация для my_enum, и вызывать нужно будет так же, boost::lexical_cast, исключение кидать только надо через boost::conversion::detail::throw_bad_cast чтобы 1:1 было и все.
Re[5]: boost::lexical_cast: из std::string в enum
От: MTD https://github.com/mtrempoltsev
Дата: 12.11.15 06:37
Оценка: +1
Здравствуйте, Igore, Вы писали:

MTD>>Главное отличие — это не lexical_cast и соответсвенно поведение может отличаться.

I>В смысле? Это просто специализация для my_enum

Именно. Вместо бустовой реализации ты предлагаешь свою, в этом и есть отличие.

I>исключение кидать только надо через boost::conversion::detail::throw_bad_cast чтобы 1:1 было и все.


Это детали реализации, которые могут меняться и ты как пользователь знать не должен.
Re: boost::lexical_cast: из std::string в enum
От: niXman Ниоткуда https://github.com/niXman
Дата: 12.11.15 18:57
Оценка:
https://github.com/niXman/enum-gen

ENUM_GEN_DECLARE_ENUM(
   my_enum
   ,
   (one)
   (two)
   (three)
)

const std::string se = enum_cast(two);
my_enum ee = enum_cast<my_enum>(se.c_str());
assert(ee == two);


если енумы уже существуют, сгенерить для них мета-инфу можно так:
ENUM_GEN_ADAPT_ENUM(
   my_enum
   ,
   (one)
   (two)
   (three)
)

сами енумы от этого не изменятся.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 12.11.2015 19:03 niXman . Предыдущая версия .
Re[2]: boost::lexical_cast: из std::string в enum
От: swingus  
Дата: 13.11.15 05:38
Оценка:
Для битовых полей не работает.

Здравствуйте, niXman, Вы писали:

X>https://github.com/niXman/enum-gen
Re[3]: boost::lexical_cast: из std::string в enum
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.11.15 09:15
Оценка:
Здравствуйте, swingus, Вы писали:

S>Для битовых полей не работает.


приведите, пожалуйста, пример.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: boost::lexical_cast: из std::string в enum
От: swingus  
Дата: 13.11.15 09:23
Оценка:

enum E
{
 flag0 = 0x1,
 flag1 = 0x2,
 flag2 = 0x4
};

E e = flag0 | flag2;


Здравствуйте, niXman, Вы писали:

X>приведите, пожалуйста, пример.
Re[5]: boost::lexical_cast: из std::string в enum
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.11.15 12:20
Оценка:
S>
S>enum E
S>{
S> flag0 = 0x1,
S> flag1 = 0x2,
S> flag2 = 0x4
S>};

S>E e = flag0 | flag2;
S>


т.е. ошибка происходит тогда, когда инклюдится enum-gen.hpp но для этого енума не генерится мета-инфа?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: boost::lexical_cast: из std::string в enum
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.11.15 12:20
Оценка:
Здравствуйте, swingus, Вы писали:

ну, или, приведите текст ошибки...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: boost::lexical_cast: из std::string в enum
От: swingus  
Дата: 13.11.15 17:10
Оценка:
Я затрудняюсь проверить, в VC++ это не компилируется, но оператор вывода для bitfield'а должен выглядеть как-то так:


enum E
{
 f0 = 0x1,
 f1 = 0x2,
 f2 = 0x4
};

std::ostream &operator << (std::ostream &ostr, E bf)
{
   if (f0 == (f0 & bf)) { ostr << "f0 "; bf &= ~f0; }
   if (f1 == (f1 & bf)) { ostr << "f1 "; bf &= ~f1; }
   if (f2 == (f2 & bf)) { ostr << "f2 "; bf &= ~f2; }
   return ostr;
}


а у вас, кажется, везде switch'и.

Здравствуйте, niXman, Вы писали:

X>Здравствуйте, swingus, Вы писали:


X>ну, или, приведите текст ошибки...
Re[7]: boost::lexical_cast: из std::string в enum
От: niXman Ниоткуда https://github.com/niXman
Дата: 20.11.15 19:14
Оценка:
Здравствуйте, swingus, Вы писали:

S>enum E

S>{
S> f0 = 0x1,
S> f1 = 0x2,
S> f2 = 0x4
S>};

S>std::ostream &operator << (std::ostream &ostr, E bf)

S>{
S> if (f0 == (f0 & bf)) { ostr << "f0 "; bf &= ~f0; }
S> if (f1 == (f1 & bf)) { ostr << "f1 "; bf &= ~f1; }
S> if (f2 == (f2 & bf)) { ostr << "f2 "; bf &= ~f2; }
S> return ostr;
S>}

не понимаю... если ваш E может быть лишь в одном из трех значений(f0/f1/f2), то зачем все эти ухищрения с битовыми операциями внутри оператора вывода?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[8]: boost::lexical_cast: из std::string в enum
От: swingus  
Дата: 20.11.15 19:38
Оценка:
У битового поля может быть сразу взведено несколько флагов. Например f0 | f1 — что выведет ваш оператор <<? И таких енумов полно в SDK, например. Я просто имею свою самописную обёртку и активно ею пользуюсь. Но меня не удовлетворяет то, что максимальное количество элементов, с которыми она справляется, несколько десятков. У вас, кстати, какое максимальное количество?


Здравствуйте, niXman, Вы писали:

X>не понимаю... если ваш E может быть лишь в одном из трех значений(f0/f1/f2), то зачем все эти ухищрения с битовыми операциями внутри оператора вывода?
Re[9]: boost::lexical_cast: из std::string в enum
От: niXman Ниоткуда https://github.com/niXman
Дата: 20.11.15 20:23
Оценка:
Здравствуйте, swingus, Вы писали:

S>Например f0 | f1 — что выведет ваш оператор <<?

результатом этой операции будет интегральный тип, а не E.

main.cxx: error: invalid conversion from 'int' to 'E' [-fpermissive]
E e = f0|f1;


к тому же, в этом случае, как выбрать нужный operator<<?

> У вас, кстати, какое максимальное количество?

256
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 20.11.2015 20:30 niXman . Предыдущая версия .
Re[10]: boost::lexical_cast: из std::string в enum
От: niXman Ниоткуда https://github.com/niXman
Дата: 20.11.15 20:27
Оценка:
Здравствуйте, niXman, Вы писали:

X>результатом этой операции будет интегральный тип, а не E.

все еще больше осложняется тем, что побитовые операции не применимы к enum class`ам.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[11]: boost::lexical_cast: из std::string в enum
От: swingus  
Дата: 21.11.15 11:06
Оценка:
Я для битовых полей я определяю битовые операции так, что они возвращают енум. Это удобно.

X>Здравствуйте, niXman, Вы писали:


X>>результатом этой операции будет интегральный тип, а не E.

X>все еще больше осложняется тем, что побитовые операции не применимы к enum class`ам.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.