Russian Qt Forum
Апрель 24, 2024, 17:39 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4   Вниз
  Печать  
Автор Тема: С++ статик поля  (Прочитано 22914 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Октябрь 08, 2015, 13:14 »

Нашёл простое решение, которое подходит для меня

Код
C++ (Qt)
class TagStatus {
public:
    enum Status {
        NoDefine,
        Define1,
        Define2
    };
    static String convertToString(Status);
    static Status convertToEnum(String);
private:
   static class HashStr: public<String,enum> {
        HashStr() {
            insert("Not define",NoDefine);
            ......
        }
   } mHashStr;
};
 

Конечно, код у меня другой, но смысл понятен.
А где convertToString? И если строчек с десяток - все равно в хедере малевать?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #16 : Октябрь 08, 2015, 13:33 »

Цитировать
Нашёл простое решение, которое подходит для меня
Тогда уж лучше так:
Код
C++ (Qt)
struct TagStatus
{
   enum Status {
       NoDefine,
       Define1,
       Define2
   };
 
   static std::string convertToString(Status s) { return get_hash().at(s); }
 
   static Status convertToStatus(const std::string & s)
   {
       for (auto & x : get_hash())
       {
           if (s == x.second)
               return x.first;
       }
       throw std::bad_cast();
   }
 
private:
   typedef std::map<Status, std::string> hash_type;
 
   static const hash_type & get_hash()
   {
       static hash_type hash =
       {
           {NoDefine, "No Define"},
           {Define1, "Define 1"},
           {Define2, "Define 2"}
       };
       return hash;
   }
};
 

Но это всё равно плохие решения, поскольку главная проблема остаётся: Править энум (что-то новое добавить, что-то удалить, что-то поменять местами или..) придётся в двух местах.
А это потенциальное узкое место, сами знаете для чего..  
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
AzazelloAV
Гость
« Ответ #17 : Октябрь 08, 2015, 13:38 »

Нашёл простое решение, которое подходит для меня

Код
C++ (Qt)
class TagStatus {
public:
    enum Status {
        NoDefine,
        Define1,
        Define2
    };
    static String convertToString(Status);
    static Status convertToEnum(String);
private:
   static class HashStr: public<String,enum> {
        HashStr() {
            insert("Not define",NoDefine);
            ......
        }
   } mHashStr;
};
 

Конечно, код у меня другой, но смысл понятен.
А где convertToString? И если строчек с десяток - все равно в хедере малевать?

А причем здесь хедер. Вынесете конструктор в спп, тем более нехорошо держать в хедере строки, хоть пару.

Ну а насчет наоборот - определите класс public<enum,String>, аналогия понятна. Можно обычный массив, если мы уверены, что енумы у нас не будут пронумерованы ручками. И конечно одна точка входа строки - т.е. строку мы определяем только раз. Другими словами консруктор будет выглядить так (если не попутал с названиями).

Код:
    mHashStr.insert(mHashEnum[enum],enum);

Большой ли оверхед - не знаю. По производительности то точно оптимально, по объёму откомпилированного кода - возможно
Записан
AzazelloAV
Гость
« Ответ #18 : Октябрь 08, 2015, 13:42 »


Но это всё равно плохие решения, поскольку главная проблема остаётся: Править энум (что-то новое добавить, что-то удалить, что-то поменять местами или..) придётся в двух местах.
А это потенциальное узкое место, сами знаете для чего..  

Это да, и тут средствами компилятора не обойтись. Остаётся только шаблон. Но с другой стороны не такое критичное, мы  можем только напортачить со строками и перекрывать данную проблему тестированием с ассертами
« Последнее редактирование: Октябрь 08, 2015, 13:46 от AzazelloAV » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #19 : Октябрь 08, 2015, 14:01 »

Вынесете конструктор ...
... определите класс ...
Да я вообще-то ничего делать не собирался - так, принял участие в обсуждении  Улыбающийся Вы же написали convertToString - вот я и спросил. Да, а если у второго класса такая же котавасия (все как TagStatus, только enum и строки другие) - тоже ему класс определять? И 2 хеша тоже создавать?

По производительности то точно оптимально...
Ой  Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #20 : Октябрь 08, 2015, 14:03 »

Цитировать
Но с другой стороны не такое критичное, мы  можем только напортачить со строками и перекрывать данную проблему тестированием с ассертами
Вы так и не ответили на мой вопрос:  где в этом случае (см. слегка переработанный код) могут возникнуть проблемы при тестировании?:
Код
C++ (Qt)
struct TagStatus
{
#define STATUS                  \
   X(NoDefine, "NoDefine")     \
   X(Define1, "Define1")      \
   X(Define2, "Define2")
 
#define X(a, b) a,
   enum Status { STATUS };
#undef X
 
   static std::string convertToString(Status s) { return get_hash().at(s); }
 
   static Status convertToStatus(const std::string & s)
   {
       for (auto & x : get_hash())
       {
           if (s == x.second)
               return x.first;
       }
       throw std::bad_cast();
   }
 
private:
   typedef std::map<Status, std::string> hash_type;
 
   static const hash_type & get_hash()
   {
#define X(a, b) {a, #b},
       static hash_type hash = { STATUS };
#undef X
       return hash;
   }
};
 
Здесь мы правил энум только в одном месте и всё.
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #21 : Октябрь 08, 2015, 14:23 »

Код
C++ (Qt)
#define X(a, b) {a, #b},
 
Что означает решетка перед b?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #22 : Октябрь 08, 2015, 14:53 »

#5 буст за собой не тащит, но... "Мои глазааа!!!"
Да и несколько энамов в одном файле не задефинировать.

#13 оптически покошерней (и функциональней, наверное, тоже) Улыбающийся но тащит буст мертвым грузом, у нас бы на конторе не прошло Грустный

Остальное, увы, треш какой-то Грустный
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #23 : Октябрь 08, 2015, 14:57 »

Цитировать
Что означает решетка перед b?
Криминальное прошлое переменной b  Смеющийся

Этот оператор # превращает b в строковый литерал (кавычки, короче, ставит двойные: "b").
Хотя в этом случае:
Код
C++ (Qt)
#define X(a, b) {a, #b},
 
он и не нужен.. можно просто
Код
C++ (Qt)
#define X(a, b) {a, b},
 
« Последнее редактирование: Октябрь 08, 2015, 15:02 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #24 : Октябрь 08, 2015, 15:15 »

Улыбающийся спс
Записан
AzazelloAV
Гость
« Ответ #25 : Октябрь 08, 2015, 16:00 »

Цитировать
Но с другой стороны не такое критичное, мы  можем только напортачить со строками и перекрывать данную проблему тестированием с ассертами
Вы так и не ответили на мой вопрос:  где в этом случае (см. слегка переработанный код) могут возникнуть проблемы при тестировании?:
Код
C++ (Qt)
struct TagStatus
{
#define STATUS                  \
   X(NoDefine, "NoDefine")     \
   X(Define1, "Define1")      \
   X(Define2, "Define2")
 
#define X(a, b) a,
   enum Status { STATUS };
#undef X
 
   static std::string convertToString(Status s) { return get_hash().at(s); }
 
   static Status convertToStatus(const std::string & s)
   {
       for (auto & x : get_hash())
       {
           if (s == x.second)
               return x.first;
       }
       throw std::bad_cast();
   }
 
private:
   typedef std::map<Status, std::string> hash_type;
 
   static const hash_type & get_hash()
   {
#define X(a, b) {a, #b},
       static hash_type hash = { STATUS };
#undef X
       return hash;
   }
};
 
Здесь мы правил энум только в одном месте и всё.

Проблемы при тестировании в вашем коде не будет.

Я имел в виду глобальные вещи. Проблемы при тестировании с макросами как таковые отсутствуют. Но на практике они трудноуловимы по совсем другим причинам:
Перегруженый код - макросы не вписываются в язык, код становится вырвиглазным.
Есть макросы "возможностей" и макросы "дебага". И чем больше макросов.... Их даже трудно с ветвлениями if сравнивать. Сколько вариантов их включения нужно протестировать со всеми остальными.

В вашем случае, это макрос, потому как макрос Улыбающийся, он был, есть и будет. Скажем так, для меня некомфортно использовать макросы прежде всего из-за 1-го пункта. Для меня ваш код понятет (ну почти), и, кстати, красив в плане решения, но всё одно вырвиглазный.

Считайте моё решение необоснованным. Я даже из за вырвиглазности готов написать шаблон, который по определению вообще адски сложно тестировать.

Мне кажется после прочтения Александреску многие программисты на С++ чуствуют себя ущербными. Но ничего, мы скоро объеденим функциональное программирование и метапрограммирование в плюсах и тогда точно не будет ни одного человека, который скажет, что знает плюсы, даже его разработчика можно засмеять.
« Последнее редактирование: Октябрь 08, 2015, 16:08 от AzazelloAV » Записан
AzazelloAV
Гость
« Ответ #26 : Октябрь 08, 2015, 16:18 »

Да, а если у второго класса такая же котавасия (все как TagStatus, только enum и строки другие) - тоже ему класс определять? И 2 хеша тоже создавать?
А как же. Разве в этом мире существуют другие решения? Не хотим ручками по правилам создавать - пишем шаблон. Нет, ну оно то конечно можно от этого отойти, привязав enum к int.

По производительности то точно оптимально...
Цитировать
Ой  Улыбающийся

Подробнее про ой. Он же статик, один раз создался и айда работать. Чем вас смущает создание хешей или мапов. Ну уж точно лучше кейсов для сотни классов, тем более для одного из хешей можно указатель использовать, а не саму строку.
« Последнее редактирование: Октябрь 08, 2015, 16:22 от AzazelloAV » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Октябрь 08, 2015, 16:54 »

А как же. Разве в этом мире существуют другие решения?
Ну вот напр вынести это в отдельный класс. Пусть пока и без шаблонов, навскидку и не вспомню когда мне потребовалось что-то другое кроме "строка + ID"

Подробнее про ой. Он же статик, один раз создался и айда работать. Чем вас смущает создание хешей или мапов.
Контейнеру нужно какое-то число эл-тов чтобы он проявил свои лучшие качества. А до десяти тупой перебор точно будет быстрее. До ста (примерно) тоже можно обойтись перебором.
Записан
AzazelloAV
Гость
« Ответ #28 : Октябрь 08, 2015, 17:03 »

Контейнеру нужно какое-то число эл-тов чтобы он проявил свои лучшие качества. А до десяти тупой перебор точно будет быстрее. До ста (примерно) тоже можно обойтись перебором.
Да это всё понятно. Я же код не в IDE пишу, а в броузере, для примера. Тут же предоставляют общие решения, ну не будет там много значений, но это частности. Главное шаблонность (не в плане шаблонов С++) и решения, а не реализация (про данный топик). Я вообще думаю массивы использовать, без всяких контейнеров. В данном случае вы переходите на другой уровень, на реализацию, которую здесь не обсуждают. Это как про хеадер.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #29 : Октябрь 09, 2015, 03:30 »

Вы так и не ответили на мой вопрос:  где в этом случае (см. слегка переработанный код) могут возникнуть проблемы при тестировании?:
Код
C++ (Qt)
struct TagStatus
{
#define STATUS                  \
   X(NoDefine, "NoDefine")     \
   X(Define1, "Define1")      \
   X(Define2, "Define2")
 
#define X(a, b) a,
   enum Status { STATUS };
#undef X
 
   static std::string convertToString(Status s) { return get_hash().at(s); }
 
   static Status convertToStatus(const std::string & s)
   {
       for (auto & x : get_hash())
       {
           if (s == x.second)
               return x.first;
       }
       throw std::bad_cast();
   }
 
private:
   typedef std::map<Status, std::string> hash_type;
 
   static const hash_type & get_hash()
   {
#define X(a, b) {a, #b},
       static hash_type hash = { STATUS };
#undef X
       return hash;
   }
};
 
Здесь мы правил энум только в одном месте и всё.
Ну я бы не назвал это впечатляющим успехом Улыбающийся Сэкономили на 4 enum,  зато потратились на #define/#undef и создали маленький ребус (не спорю - элегантный, остроумный) который потребует осмысления. Пусть менее минуты - но все же.

И еще мне несимпатично: когда браузер вывел меня на объявление члена hash - хотелось бы сразу видеть чем он инициализируется. А тут надо подыматься вверх для обозрения STATUS

И содержательная часть (ф-ционал) как-то заслонена "синтаксическим сахаром". По одному ищем с ключом, по другому перебором - неоднообразно. Заряжали бы уж сразу boost::bitmap.
Записан
Страниц: 1 [2] 3 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.228 секунд. Запросов: 23.