LINUX.ORG.RU

[c++][qt] Как уйти от if else?

 ,


0

3

Есть такой быдлокод (моего авторства :) ):

if(e.attribute(«get») == «statement_serial») {
drawElement(e, getStatement()->getStatementSerial(), fontFamily, fontSize);
} else if(e.attribute(«get») == «statement_number») {
drawElement(e, getStatement()->getStatementNumber(), fontFamily, fontSize);
} else if(e.attribute(«get») == «notification_serial») {
drawElement(e, getStatement()->getNotificationSerial(), fontFamily, fontSize);
} else if(e.attribute(«get») == «notification_number») {
drawElement(e, getStatement()->getNotificationNumber(), fontFamily, fontSize);
} else if(e.attribute(«get») == «assured_fio») {
drawElement(e, getStatement()->getAssuredFio(), fontFamily, fontSize);
} else if(e.attribute(«get») == «assured_address_index») {
drawElement(e, getStatement()->getAssuredAddressIndex(), fontFamily, fontSize);
} else if(e.attribute(«get») == «assured_address») {
drawElement(e, getStatement()->getAssuredAddress(), fontFamily, fontSize);
} else if(e.attribute(«get») == «assured_phone») {
drawElement(e, getStatement()->getAssuredPhone(), fontFamily, fontSize);
} else if(e.attribute(«get») == «apartment_address_index») {
drawElement(e, getStatement()->getApartmentAddressIndex(), fontFamily, fontSize);
} else if(e.attribute(«get») == «apartment_address»){
drawElement(e, getStatement()->getApartmentAddress(), fontFamily, fontSize);
}

Поясню в чём суть: есть XML'ный тег, который говорит, мол, нарисуй такой-то элемент, информацию возьми из параметра «get». Далее проходим ифами и, если название совпало, получаем информацию из соответствующего метода класса Statement.

Собственно вопрос: можно ли как-то уйти от if else и написать что-то более изящное?

★★

учи про std::map( вероятно в Qt - QMap ) + указатели на функции/методы

П.С. а за

...
else if(e.attribute(«get») == «notification_number»
...
else if(e.attribute(«get») == «assured_address_index»)
...

надо руки отрывать

anonymous
()

Это даже неэффективно. Можно все свести к отображению (map) строки на функцию двух аргументов (fontFamily, fontSize). Сначала где-то создаем map, а потом проверяем, нет ли нужной функции обработки в этом map по заданному атрибуту. Будет работать, если все можно свести к общему набору аргументов (как в твоем примере).

dave ★★★★★
()
Ответ на: комментарий от dave

Да, аргументов может быть больше. Е тоже напрашивается.

dave ★★★★★
()

ах да, а еще тут можно нехило так оптимизировать путем написания универсального геттера вместо getApartmentAddress() и прочих.

isden ★★★★★
()
Ответ на: комментарий от isden

> мсье не в курсе про switch()/case ?

Со строками? Разве что через какой-нибудь qHash(const QString&).

rival ★★
()

Как самый дебильный вариант, ну кроме свитча на строки.

int index = getStatement()->metaObject()->indexOfMethod(QMetaObject::normalizedSignature("get"+e.attribute("get")+"()"));
QMetaMethod method = getStatement()->metaObject()->method(index);
drawElement(e, method.invoke(getStatement()), fontFamily, fontSize);

zJes ★★
()
Ответ на: комментарий от namezys

А то. :)

Пусть будет хоть какое-то использование меты.
А тащить буст ради свитча сомнительное удовольствие. :)

zJes ★★
()
Ответ на: комментарий от anonymous

>учи про std::map( вероятно в Qt - QMap ) + указатели на функции/методы

спасибо, подохдит!

SaBo ★★
() автор топика
Ответ на: комментарий от flareguner

Меня как-то просили как раз избавиться от свича на несколько экранов)

slackwarrior ★★★★★
()

Предыдущие ораторы насоветовали фигни.

Правильно так: всякие statement_serial сделай свойствами statement'а. Для этого в определении класса Statement пишешь такое

Q_PROPERTY(ТИП statement_serial READ getStatementSerial WRITE setStatementSerial);

Часть WRITE setStatementSerial можно и пропустить, если свойство предназначено только для чтения.

После этого твоя гроздь if'ов превращается
const QString prop = e.attribute(«get»);
drawElement(e, getStatement()->property(prop), fontFamily, fontSize);

Кроме того, при таком подходе даром получаешь интеграцию своих Statement'ов с QtScript и QtWebKit в том смысле, что нужные свойства можно будет дергать из javascript'а.

anonymous
()

а потом будут говорить, что функциональные языки не нужны.

anonymous
()
Ответ на: комментарий от namezys

Не тяжёл, но здесь ненужен.

#include <string>
#include <cstdlib>
#include <map>
#include <iostream>
using std::string;

/* начало эмуляции API ======================================= */

int myrand(int from, int to)
{
    return (float(rand())/RAND_MAX)*(to-from)+from;
}
#define LEN(x) (sizeof(x)/sizeof(*x))

class SomeData {};

class Statement
{
public:
    SomeData getStatementSerial() { return SomeData(); }
    SomeData getStatementNumber() { return SomeData(); }
    SomeData getNotificationSerial() { return SomeData(); }
    SomeData getNotificationNumber() { return SomeData(); }
    SomeData getAssuredFio() { return SomeData(); }
    SomeData getAssuredAddressIndex() { return SomeData(); }
    SomeData getAssuredAddress() { return SomeData(); }
    SomeData getAssuredPhone() { return SomeData(); }
    SomeData getApartmentAddressIndex() { return SomeData(); }
    SomeData getApartmentAddress() { return SomeData(); }
};

Statement * getStatement() { static Statement s; return &s;} 

class SomeE
{
    static char const * const ATTRIBUTES[];
public:
    string attribute(const string & which);
};

char const * const SomeE::ATTRIBUTES[] = {
    "statement_serial",
    "statement_number",
    "notification_serial",
    "notification_number",
    "assured_fio",
    "assured_address_index",
    "assured_address",
    "assured_phone",
    "apartment_address_index",
    "apartment_address",
};

string SomeE::attribute(const string & )
{
    return ATTRIBUTES[myrand(0,LEN(ATTRIBUTES))];
}

class SomeFontFamily {};
class SomeFontSize {};
SomeE e;
SomeFontFamily fontFamily;
SomeFontSize fontSize;

void drawElement(SomeE, SomeData, SomeFontFamily, SomeFontSize) {}

/* конец эмуляции API ======================================= */



int main()
{
    // составляем карту:
    typedef SomeData (Statement::*attrib_getter)();
    typedef std::pair <char const * const, attrib_getter> ATTR_DEF;
    ATTR_DEF ATTRIBUTES[] = {
    //можно убрать эти "ATTR_DEF" и и заменить круглые скобки на фигурные, но ворнинги появляются
        ATTR_DEF("statement_serial",        &Statement::getStatementSerial        ),
        ATTR_DEF("statement_number",        &Statement::getStatementNumber        ),
        ATTR_DEF("notification_serial",        &Statement::getNotificationSerial    ),
        ATTR_DEF("notification_number",        &Statement::getNotificationNumber    ),
        ATTR_DEF("assured_fio",            &Statement::getAssuredFio        ),
        ATTR_DEF("assured_address_index",    &Statement::getAssuredAddressIndex    ),
        ATTR_DEF("assured_address",        &Statement::getAssuredAddress        ),
        ATTR_DEF("assured_phone",        &Statement::getAssuredPhone        ),
        ATTR_DEF("apartment_address_index",    &Statement::getApartmentAddressIndex    ),
        ATTR_DEF("apartment_address",        &Statement::getApartmentAddress        ),
    };
    //инициализируем карту массивом пар:
    std::map<string, attrib_getter> ATTR_MAP(ATTRIBUTES,ATTRIBUTES+LEN(ATTRIBUTES));
    //используем:
    string attribute = e.attribute("get");
    attrib_getter getter = ATTR_MAP[attribute];
    SomeData statement = (getStatement()->*getter)();
    drawElement(e, statement, fontFamily, fontSize);
    std::cout << attribute << std::endl;
    //то-же самое одной строкой:
    drawElement(e, (getStatement()->*ATTR_MAP[e.attribute("get")])(), fontFamily, fontSize);
}
legolegs ★★★★★
()

Какой только херотой не страдают когда нормальных макросов нет.
Словари! С указатели на функции!! Иерархии классов!

А потом еще возникают вопросы, че ж это все программы сложнее хелловордов, написанные на плюсах, так тормозят, несмотря на охрененные оптимизирующие компиляторы?

Love5an
()
Ответ на: комментарий от anonymous

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

Love5an
()

State machines или конечные автоматы ещё никто не советовал?
На QML или Ragel, bison...

anonymous
()
Ответ на: комментарий от namezys

>Максров Что?

PS аноним прав, надо заассертить getter.

legolegs ★★★★★
()
Ответ на: комментарий от Love5an

На практике, эти свитчи часто плодятся. Поддерживать уже пяток свичей - совершенно не интересно.

legolegs ★★★★★
()
Ответ на: комментарий от Love5an

> словарь с коллбэками для замены фактически статического свитча это трындец. При чем тут питон?

Статический switch быстро делается только на целочисленных переменных. Или есть в этом сомнения?

namezys ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.