Как бы сделать такие enum 'ы..
От: Аноним  
Дата: 31.01.08 12:57
Оценка:
В оконном приложении в циркулируют сообщения Command(самопальная диспетчеризация):
enum CommandKind{
   APP_INIT
  ,APP_CLOSE
  ..
};
struct Command{
  ComandKind kind;
};

И вот хочеться эти сообщения логировать как-то так:

void OnCommand(Command& cmd)
{
switch( cmd.kind ){
 case APP_INIT:  /*логируем "APP_INIT"*/  break; 
 case APP_CLOSE: /*логируем "APP_CLOSE"*/ break; 
};
}


Как-бы так ассоциировать с кодом команды строчку текста ? Мне приходит в голову
что-то такое:
struct Command {
  ComandKind kind;
  const char* text;
  ComandK(ComandKind kind,const char* msg):kind(kind),msg(msg){}
}   AppInit(APP_INIT,"APP_INIT")    //можно макросом
   ,AppClose(APP_CLOSE,"APP_CLOSE")
   ..
   ;

Но тут приходиться вручную создавать объекты Command, что неудобно.
Есть ли решение лучше ?
Re: Как бы сделать такие enum 'ы..
От: Аноним  
Дата: 31.01.08 13:25
Оценка:
Это стандартная проблема на С++ проектах, как конвертировать enum'ы с строки и обратно.

Один из варинтов примерно такой:
class CommandKind
{
  public:

  enum Id
  {
     APP_INIT,
     APP_CLOSE
  };

  std::string toString( Id id )
  {
     switch( id )
     {
     case APP_INIT:  return std::string("APP_INIT"); 
     case APP_CLOSE:  return std::string("APP_CLOSE"); 
     }
     return std::string("Undefind id")
  }

  Id fromString( const std::string& idAsString );
}


Какое бы ты решение не выбрал, всегда придется писать какой-то код.
Но поскольку он всегда одинаков, то это дело можно очень хорошо автоматизировать
и быстро налабать какой-нибудь скриптик, которые подобные классы генерит автоматически...
Re: Как бы сделать такие enum 'ы..
От: NailS Россия  
Дата: 31.01.08 13:31
Оценка:
...
А>Как-бы так ассоциировать с кодом команды строчку текста ? Мне приходит в голову
Например, написать функцию, которая будет по коду enum-а возвращать его текстовое описание,
в функции связывать текст с кодом через switch-case или массив описаний (если коды от нуля и
больше, и без разрывов).
...
А>Есть ли решение лучше ?
Например, так
http://lists.pilot-link.org/pipermail/pilot-link-devel/2005-April/001344.html
Re: Как бы сделать такие enum 'ы..
От: AndryBlack Россия  
Дата: 31.01.08 13:40
Оценка: 4 (2)
Здравствуйте, Аноним, Вы писали:


А>Как-бы так ассоциировать с кодом команды строчку текста ? Мне приходит в голову

А>что-то такое:
А>
А>struct Command {
А>  ComandKind kind;
А>  const char* text;
А>  ComandK(ComandKind kind,const char* msg):kind(kind),msg(msg){}
А>}   AppInit(APP_INIT,"APP_INIT")    //можно макросом
А>   ,AppClose(APP_CLOSE,"APP_CLOSE")
А>   ..
А>   ;
А>

А>Но тут приходиться вручную создавать объекты Command, что неудобно.
А>Есть ли решение лучше ?

если Ваша "религия" позволяет активно использовать препроцессор, то например так:
// file commands.inc
COMMAND( APP_INIT )
COMMAND( APP_CLOSE )
/*...*/

enum CommandKind
{
#define COMMAND( NAME ) NAME ,
#include "commands.inc"
#undef COMMAND
};
const char* CommandNames[] =
{
#define COMMAND( NAME ) #NAME ,
#include "commands.inc"
#undef COMMAND
};
Re[2]: Как бы сделать такие enum 'ы..
От: shvonder Россия  
Дата: 31.01.08 14:38
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Один из варинтов примерно такой:
А>
А>  std::string toString( Id id )
А>  {
А>     switch( id )
А>     {
А>     case APP_INIT:  return std::string("APP_INIT"); 
А>     case APP_CLOSE:  return std::string("APP_CLOSE"); 
А>     }
А>     return std::string("Undefind id")
А>  }
А>

Думал об этом но это ещё муторнее и чревать ошибками.
Re[2]: Как бы сделать такие enum 'ы..
От: shvonder Россия  
Дата: 31.01.08 14:41
Оценка:
Здравствуйте, NailS, Вы писали:

NS>Например, написать функцию, которая будет по коду enum-а возвращать его текстовое описание,

NS>в функции связывать текст с кодом через switch-case или массив описаний (если коды от нуля и
NS>больше, и без разрывов).
Муторно

А>>Есть ли решение лучше ?

NS>Например, так
NS>http://lists.pilot-link.org/pipermail/pilot-link-devel/2005-April/001344.html
С лёту не понял, нужно разобраться..
Re[2]: Как бы сделать такие enum 'ы..
От: shvonder Россия  
Дата: 31.01.08 14:43
Оценка:
Здравствуйте, AndryBlack, Вы писали:

AB>Здравствуйте, Аноним, Вы писали:

AB>если Ваша "религия" позволяет активно использовать препроцессор, то например так:
AB>
AB>// file commands.inc
AB>COMMAND( APP_INIT )
AB>COMMAND( APP_CLOSE )
AB>/*...*/

AB>

AB>
AB>enum CommandKind
AB>{
AB>#define COMMAND( NAME ) NAME ,
AB>#include "commands.inc"
AB>#undef COMMAND
AB>};
AB>const char* CommandNames[] =
AB>{
AB>#define COMMAND( NAME ) #NAME ,
AB>#include "commands.inc"
AB>#undef COMMAND
AB>};
AB>


Нужно попробовать, хотя страшновато
Re[3]: Как бы сделать такие enum 'ы..
От: Аноним  
Дата: 31.01.08 14:55
Оценка: -1
Здравствуйте, shvonder, Вы писали:

S>Думал об этом но это ещё муторнее и чревать ошибками.


На С++ ничего принципиально другого не сделаешь...
Ну нету в С++ метаданных, рефлекшена и других подобных вещей.

А ошибками это не чревато, если генерацию таких классов автоматизировать
на основе внешнего описания.
Как только у тебя будут все скрипты и все будет автоматизировано,
то разницы не будет, где редактировать твой enum, в каком-то h файле,
или в каком-то внешнем txt/xml файле

Ну а если все равно муторно, то ты профессию не ту выбрал, ну или как минимум язык.
Пиши на шарпе или управляемом С++. Там это все на шару будет
Re: Как бы сделать такие enum 'ы..
От: nen777w  
Дата: 31.01.08 15:35
Оценка: :)
гм... может это поможет

#define E2S( e ) #e
enum E{ ENUM1, ENUM2 };

cout << E2S( ENUM1 );
Re[2]: Как бы сделать такие enum 'ы..
От: bkat  
Дата: 31.01.08 15:46
Оценка:
Здравствуйте, nen777w, Вы писали:

N>гм... может это поможет


N>#define E2S( e ) #e

N>enum E{ ENUM1, ENUM2 };

N>cout << E2S( ENUM1 );


Да, да "поможет"...
Особенно в такой ситуации

enum E{ ENUM1, ENUM2 };
E id = ENUM1;
cout << E2S( id );
Re[3]: Как бы сделать такие enum 'ы..
От: shvonder Россия  
Дата: 01.02.08 09:47
Оценка:
S>Здравствуйте, AndryBlack, Вы писали:

AB>>Здравствуйте, Аноним, Вы писали:

AB>>если Ваша "религия" позволяет активно использовать препроцессор, то например так:
Поразмыслив, принял ваш вариант. Мало нажатий клавиш , очень просто (в отличие от предложения NailS'а) и для моих целей хватит.
Хотя, конечно, варварски.
Re[4]: Как бы сделать такие enum 'ы..
От: alzt  
Дата: 01.02.08 10:55
Оценка:
Здравствуйте, Аноним, Вы писали:

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


S>>Думал об этом но это ещё муторнее и чревать ошибками.


А>На С++ ничего принципиально другого не сделаешь...

А>Ну нету в С++ метаданных, рефлекшена и других подобных вещей.

А>А ошибками это не чревато, если генерацию таких классов автоматизировать

А>на основе внешнего описания.
А>Как только у тебя будут все скрипты и все будет автоматизировано,
А>то разницы не будет, где редактировать твой enum, в каком-то h файле,
А>или в каком-то внешнем txt/xml файле

А>Ну а если все равно муторно, то ты профессию не ту выбрал, ну или как минимум язык.

А>Пиши на шарпе или управляемом С++. Там это все на шару будет

Кстати писать
switch( id )
     {
     case APP_INIT:  return std::string("APP_INIT"); 
     case APP_CLOSE:  return std::string("APP_CLOSE"); 
     }

не так уж и плохо, как кажется (т.е. отдельно писать константу и её целочисленное значение, а не использовать метаданные).
Я как-то писал для себя программу на C# и задумал локализовать её.
Мне надо было вывести названия цветов — по английски не проблема, получить список всех доступных цветов легко можно, но что делать с русским языком?
Я не смог найти хороший способ вывести список всех доступных цветов на русском языке кроме как самому вбить их.
А для своих enum тем более потребуется вводить.
Re[4]: Как бы сделать такие enum 'ы..
От: Vain Россия google.ru
Дата: 01.02.08 13:29
Оценка:
Здравствуйте, shvonder, Вы писали:

AB>>>если Ваша "религия" позволяет активно использовать препроцессор, то например так:

S>Поразмыслив, принял ваш вариант. Мало нажатий клавиш , очень просто (в отличие от предложения NailS'а) и для моих целей хватит.
S>Хотя, конечно, варварски.
А вот так пойдёт?
#include "boost/preprocessor.hpp"

//Declaring our enum
#define ENUM_SEQ_COMMAND_KIND\
  (((APP_INIT)        (1) )   ("APP_INIT_BLA_BLA"))\
  (((APP_CLOSE)       (10)))\
  (((APP_ABRACADABRA)     )   ("Strange message"))\
  (((APP_TERMINATE)       ))

//Decryption:
//<Enum>          ->  <EnumIntValue>  -> <EnumStringValue>
//APP_INIT        ->              1   -> "APP_INIT_BLA_BLA"
//APP_CLOSE       ->             10   -> "APP_CLOSE"
//APP_ABRACADABRA ->             11   -> "Strange message"
//APP_TERMINATE   ->             12   -> "APP_TERMINATE"
//
//Format:
//(((<Enum>) [(<EnumIntValue>)]) [(<EnumStringValue>)])
//  Where,
//  [] - optional sequence argument.
//
//Features:
// 1. Both <EnumIntValue> and <EnumStringValue> - are optional.
// 2. If <EnumIntValue> in first enum doesn't typed, then it would be - 0 (zero).
// 3. If <EnumIntValue> in non first enum doesn't typed, then it would be previous enum value plus 1 (<EnumIntValue>+1).
//

// Generate single enumeration
#define _GENERATE_ENUM_FROM_SEQ(z,n,enums_seq)\
  BOOST_PP_IF(n,BOOST_PP_COMMA,BOOST_PP_EMPTY)() BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(n,enums_seq)))\
  BOOST_PP_IF(BOOST_PP_GREATER_EQUAL(BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(n,enums_seq))),2),\
    = BOOST_PP_SEQ_ELEM(1,BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(n,enums_seq))),\
    BOOST_PP_IF(n,\
      = BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(n),enums_seq)))+1 BOOST_PP_EMPTY,\
      BOOST_PP_EMPTY)())

// Generate multiple enumeration
#define GENERATE_ENUMS_FROM_SEQ(enums_seq)\
  BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(enums_seq),_GENERATE_ENUM_FROM_SEQ,enums_seq)

// Generate single case
#define _GENERATE_ENUM_TO_STRING_CASE_2(z,n,enum_seq)\
  case BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(0,enum_seq)): return \
  BOOST_PP_MACRO_IF(BOOST_PP_GREATER_EQUAL(BOOST_PP_SEQ_SIZE(enum_seq),2),\
    (1,enum_seq),\
    (BOOST_PP_SEQ_ELEM(0,BOOST_PP_SEQ_ELEM(0,enum_seq))),\
    BOOST_PP_SEQ_ELEM,\
    BOOST_PP_STRINGIZE);

#define _GENERATE_ENUM_TO_STRING_CASE_1(z,n,enums_seq)\
  _GENERATE_ENUM_TO_STRING_CASE_2(z,n,BOOST_PP_SEQ_ELEM(n,enums_seq))

// Generate multiple cases
#define GENERATE_ENUMS_TO_STRING_CASES(enums_seq)\
  BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(enums_seq),_GENERATE_ENUM_TO_STRING_CASE_1,enums_seq)

// Begin of usage
enum CommandKind {
  GENERATE_ENUMS_FROM_SEQ(ENUM_SEQ_COMMAND_KIND)
};

const char* GetString(CommandKind e) {
  switch(e) {
    GENERATE_ENUMS_TO_STRING_CASES(ENUM_SEQ_COMMAND_KIND)
  }
  return 0;
}


После препроцессинга, это будет выглядить примерно так:
enum CommandKind {
   APP_INIT  = 1 ,
   APP_CLOSE  = 10 ,
   APP_ABRACADABRA  = APP_CLOSE +1 ,
   APP_TERMINATE  = APP_ABRACADABRA +1
};

const char* GetString(CommandKind e) {
  switch(e) {
    case APP_INIT : return "APP_INIT_BLA_BLA";
    case APP_CLOSE : return "APP_CLOSE";
    case APP_ABRACADABRA : return "Strange message";
    case APP_TERMINATE : return "APP_TERMINATE";
  }
  return 0;
}


BOOST_PP_MACRO_IF нужен из-за проблемы с варнингами, т.к. в BOOST_PP_IF expand'ятся оба аргумента внезависимости от условия, когда нужно чтобы экспандился только один при разных макросах. Возьмёте его здесь
Автор: Vain
Дата: 22.12.07
.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[5]: Как бы сделать такие enum 'ы..
От: shvonder Россия  
Дата: 01.02.08 13:56
Оценка:
Здравствуйте, Vain, Вы писали:

V>А вот так пойдёт?

Чуть менее варварски, но гораздо менее читабельно.
Re[6]: Как бы сделать такие enum 'ы..
От: Vain Россия google.ru
Дата: 01.02.08 17:37
Оценка:
Здравствуйте, shvonder, Вы писали:

V>>А вот так пойдёт?

S>Чуть менее варварски, но гораздо менее читабельно.
Вам надо читать только вот это:
//Declaring our enum
#define ENUM_SEQ_COMMAND_KIND\
  (((APP_INIT)        (1) )   ("APP_INIT_BLA_BLA"))\
  (((APP_CLOSE)       (10)))\
  (((APP_ABRACADABRA)     )   ("Strange message"))\
  (((APP_TERMINATE)       ))

// Begin of usage
enum CommandKind {
  GENERATE_ENUMS_FROM_SEQ(ENUM_SEQ_COMMAND_KIND)
};

const char* GetString(CommandKind e) {
  switch(e) {
    GENERATE_ENUMS_TO_STRING_CASES(ENUM_SEQ_COMMAND_KIND)
  }
  return 0;
}

И это гораздо эффективнее, т.к. можно написать/дописать к ENUM_SEQ_COMMAND_KIND всё что угодно.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: Как бы сделать такие enum 'ы..
От: Erop Россия  
Дата: 01.02.08 18:44
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>enum CommandKind{
А>   APP_INIT
А>  ,APP_CLOSE
А>  ..
А>};
А>

А>Есть ли решение лучше ?

Есть, например, такое решение:
enum CommandKind {
    CK_INIT, 
    CK_CLOSE, 
    CK_COUNT
};

extern const char* EnumStr( CommandKind );


и в cpp
#define ENUM_STR_ENTRY( name ) case name: return #name;
const char* EnumToStr( CommandKind id )
{
    StaticAssert( CK_COUNT == 2 );
    switch( id ) {
        ENUM_STR_ENTRY( CK_INIT );
        ENUM_STR_ENTRY( CK_CLOSE );
        ENUM_STR_ENTRY( CK_COUNT );
    }
    assert( false );
    return "BadValue";
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Как бы сделать такие enum 'ы..
От: Alex Alexandrov США  
Дата: 03.02.08 18:45
Оценка:
Здравствуйте, AndryBlack, Вы писали:

AB>если Ваша "религия" позволяет активно использовать препроцессор, то например так:

AB>
AB>// file commands.inc
AB>COMMAND( APP_INIT )
AB>COMMAND( APP_CLOSE )
AB>/*...*/

AB>

AB>
AB>enum CommandKind
AB>{
AB>#define COMMAND( NAME ) NAME ,
AB>#include "commands.inc"
AB>#undef COMMAND
AB>};
AB>const char* CommandNames[] =
AB>{
AB>#define COMMAND( NAME ) #NAME ,
AB>#include "commands.inc"
AB>#undef COMMAND
AB>};
AB>


Как-то использовал сходные конструкции, только вместо включения файла было что-то вроде

#define COMMAND_LIST     \
    COMMAND( APP_INIT )  \
    COMMAND( APP_CLOSE )

enum CommandKind
{
#define COMMAND( NAME ) NAME ,
COMMAND_LIST
#undef COMMAND
};
const char* CommandNames[] =
{
#define COMMAND( NAME ) #NAME ,
COMMAND_LIST
#undef COMMAND
};


Нравилось тем, что легко поддерживать. Отказался из-за того, что члены перечисления невозможно стало документировать Doxygen-ом. Откатился на обычный вариант (Егор его описал тут где-то рядом) с жестким ассертом в default:
It's kind of fun to do the impossible (Walt Disney)
Re: Как бы сделать такие enum 'ы..
От: Stormblast http://www.myspace.com/stormblastblack
Дата: 12.02.08 12:30
Оценка: 3 (1)
Здравствуйте, Аноним, Вы писали:

Может быть поможет быть ...
конечно не так красиво как enum в Java, но все же ...


#ifndef ENUMERATION_H_
#define ENUMERATION_H_

class Enumeration {
private:
    static int count;
    const char *name;
    int value;

public:
    Enumeration() : value(0), name(0) {
    }
    
    Enumeration(const char *name) :    value(count) {
        this->name = name;
        count++;
    }

    Enumeration(const Enumeration &obj) :
        value(obj.value) {
        name = obj.name;
    }

    int getValue() const {
        return value;
    }

    const char *getName() const {
        return name;
    }
    
    bool operator ==(const Enumeration &obj) const {
        return (name == obj.name && value == obj.value);
    }

    bool operator !=(const Enumeration &obj) const {
        return (name != obj.name && value != obj.value );
    }
};

#endif /*ENUMERATION_H_*/

//cpp

#include "Enumeration.h"


int Enumeration::count = 0;



#ifndef MYENUM_H_
#define MYENUM_H_

#include "Enumeration.h"

class MyEnum : public Enumeration
{
public:
public:
    MyEnum(const char *name) : Enumeration(name) {}
  
    static const MyEnum ACTIVE;
    static const MyEnum SUSPEND;
    static const MyEnum OFF;
};

#endif /*MYENUM_H_*/

//cpp

#include "MyEnum.h"

const MyEnum MyEnum::ACTIVE("ACTIVE");
const MyEnum MyEnum::SUSPEND("SUSPEND");
const MyEnum MyEnum::OFF("OFF");


// use

#include <iostream>
#include "MyEnum.h"
using namespace std;



int main() 
{
    const Enumeration enumeration =  MyEnum::ACTIVE;

    cout << "Type : " << enumeration.getName() << endl; 
    
    return 0;
}


только интерфейс нужно сделать ...
ну и написать правильный equals(), недостаток что имена могут быть одинаковы ...
Re: Как бы сделать такие enum 'ы..
От: wtom  
Дата: 12.02.08 14:02
Оценка:
Здравствуйте, Аноним, Вы писали:

enum CommandKind{
   APP_INIT = 0
  ,APP_CLOSE = 1
  .. = 2
};

const char* command_names[] =
{
"APP_INIT"
, "APP_CLOSE"
,
};

...

CommandKind cmd = APP_INIT;


command_names[cmd] — это "APP_INIT"

?
Не стоит переходить реку вброд, если известно только, что ее глубина (средняя) 4 фута.
Re[2]: Как бы сделать такие enum 'ы..
От: shvonder Россия  
Дата: 12.02.08 14:53
Оценка:
Здравствуйте, wtom, Вы писали:

W>Здравствуйте, Аноним, Вы писали:

W>
W>enum CommandKind{
W>   APP_INIT = 0
W>  ,APP_CLOSE = 1
W>  .. = 2
W>};
W>const char* command_names[] =
W>{
W>"APP_INIT"
W>, "APP_CLOSE"
W>,
W>};
W>

W>command_names[cmd] — это "APP_INIT"
Ну что вы в самом деле! Имеем:
enum CommandKind{
   APP_INIT
  // 3 страницы текста
  TOTAL
};
const char* command_names[] =
{
"APP_INIT"
//3 страницы текста
};
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.