Форум программистов, компьютерный форум CyberForum.ru

Какой паттерн подойдет, чтобы избежать длинных ветвлений? - C++

Восстановить пароль Регистрация
 
tapochka
34 / 34 / 8
Регистрация: 25.04.2014
Сообщений: 449
14.07.2016, 23:27     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #1
здравствуйте, есть код схематично такой:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class CTest_base {
public:
    CTest_base() : vec() {}
    virtual ~CTest_base() noexcept {}
    //something else
protected:
    std::vector<int> vec;
};
 
class CTest : public CTest_base {
public:
    CTest() : a(0) {}
    ~CTest() noexcept {}
    //something else
    void set() {
        if(a==2)
            vec.shrink_to_fit();
        else if(a==3)
            vec.clear();
        else if(a==4)
            vec.resize(5);
        else 
            vec.emplace_back(0);
    }
    void set_a(int&& a) {
        this->a = std::move(a);
    }
private:
    int a;
};
какой паттерн применить в таких случаях чтобы избегать длинных ветвлений в рантайме? шаблоны не подходят т.к. в рантайме вызывается set_a... observer и template method вроде не подходят... как быть?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.07.2016, 23:27     Какой паттерн подойдет, чтобы избежать длинных ветвлений?
Посмотрите здесь:

C++ Builder Какой компонент типа статус бара, подойдет для отображения дробного значения процента?
Прошу привести пример ветвлений Visual C++
Какой компонент надо подключить чтобы работало NMHTTP1? C++ Builder
Какой тип лучше всего подойдет для числа? C++
C++ Массивы. Определить, какой банк выбрать, чтобы выгодно обменять доллары на рубли
Какой софт нужен, чтобы начать программировать на C++ C++
C++ Какой заголовочный файл нужно подключить чтобы стали доступны int32_t size_t ?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
hoggy
5602 / 2232 / 411
Регистрация: 15.11.2014
Сообщений: 5,025
Завершенные тесты: 1
14.07.2016, 23:33     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #2
Цитата Сообщение от tapochka Посмотреть сообщение
какой паттерн применить в таких случаях чтобы избегать длинных ветвлений в рантайме?
switch case ?
tapochka
34 / 34 / 8
Регистрация: 25.04.2014
Сообщений: 449
14.07.2016, 23:35  [ТС]     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #3
Цитата Сообщение от hoggy Посмотреть сообщение
switch case
ооп-шное что-нибудь
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
12282 / 6969 / 784
Регистрация: 27.09.2012
Сообщений: 17,282
Записей в блоге: 2
Завершенные тесты: 1
14.07.2016, 23:38     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #4
Цитата Сообщение от tapochka Посмотреть сообщение
как быть?
как вариант - сделать какой-нибудь any с реализацией type erasure,
запихать туда std::function и сделать map/vector/array из any с разными "функциями" внутри.

Еще вариант - map/vector/array с std::function/функциями типа void(std::vector&).
Затем arr[a](vec);. Каждая "функция" вызывает что нужно у вектора.
DrOffset
6786 / 3997 / 917
Регистрация: 30.01.2014
Сообщений: 6,818
14.07.2016, 23:39     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #5
tapochka, ООП-шное - это передавать не интовое состояние в класс, а Actor, у которого есть соответствующе определенная операция по работе с vec.
hoggy
5602 / 2232 / 411
Регистрация: 15.11.2014
Сообщений: 5,025
Завершенные тесты: 1
14.07.2016, 23:41     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #6
Цитата Сообщение от tapochka Посмотреть сообщение
ооп-шное что-нибудь
ну если вам нужен ооп ради ооп, и ради этого вы готовы просадить перфоманс,
замедлив работу без какой либо необходимости,
то можете использовать классический подход:

C++
1
2
3
4
5
std::map<key, std::unique_ptr<ICommand> > commands;
 
...
 
commands[a]->work();
а потом лепить наследников на каждый чих.

кода придется написать больше.
памяти жрать будет больше.
работать будет медленнее.

кстати, белая магия компилятора так же способна в некоторых случаях
представить свитч-кейс в виде ассоциативного массива.
вот только без потерь перфоманса.
tapochka
34 / 34 / 8
Регистрация: 25.04.2014
Сообщений: 449
14.07.2016, 23:46  [ТС]     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #7
Цитата Сообщение от Croessmah Посмотреть сообщение
как вариант - сделать какой-нибудь any с реализацией type erasure,
запихать туда std::function и сделать map/vector/array из any с разными "функциями" внутри.
ну имелось ввиду не только с++... если любой ооп-поддерживаемый язык брать

хотя ваша идея прикольная... да и мастерить никакой any не надо, все же есть в бусте по крайней мере...

Добавлено через 2 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
ну если вам нужен ооп ради ооп, и ради этого вы готовы просадить перфоманс,
замедлив работу без какой либо необходимости,
ну просто в моем случае один метод ну слишком уродский получается через ветвления

Цитата Сообщение от hoggy Посмотреть сообщение
кстати, белая магия компилятора так же способна в некоторых случаях
представить свитч-кейс в виде ассоциативного массива.
да читал вроде всегда так компилятор поступает... не проверял правда

Добавлено через 1 минуту
Цитата Сообщение от DrOffset Посмотреть сообщение
tapochka, ООП-шное - это передавать не интовое состояние в класс, а Actor, у которого есть соответствующе определенная операция по работе с vec.
можете плз на коленках набросок кинуть?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
12282 / 6969 / 784
Регистрация: 27.09.2012
Сообщений: 17,282
Записей в блоге: 2
Завершенные тесты: 1
14.07.2016, 23:47     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #8
Цитата Сообщение от tapochka Посмотреть сообщение
можете плз на коленках набросок кинуть?
В принципе, тоже самое, что и hoggy привел.
Разница в деталях разве что.
hoggy
5602 / 2232 / 411
Регистрация: 15.11.2014
Сообщений: 5,025
Завершенные тесты: 1
14.07.2016, 23:49     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #9
Цитата Сообщение от tapochka Посмотреть сообщение
ну просто в моем случае один метод ну слишком уродский получается через ветвления
если ключи идут строго друг за другом,
то можно сделать обычный вектор акторов std::function

C++
1
2
3
4
std::vector< std::function<void()> > actors;
 
actors.emplace_back(  [&vec](){ vec.shrink_to_fit();  }  );
actors.at(a)();
tapochka
34 / 34 / 8
Регистрация: 25.04.2014
Сообщений: 449
14.07.2016, 23:57  [ТС]     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #10
вот думал что-то типа tag-dispatching... прикрутить бы(из инета код)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace std {
  struct input_iterator_tag { };
  struct bidirectional_iterator_tag : input_iterator_tag { };
  struct random_access_iterator_tag : bidirectional_iterator_tag { };
 
  namespace detail {
    template <class InputIterator, class Distance>
    void advance_dispatch(InputIterator& i, Distance n, input_iterator_tag) {
      while (n--) ++i;
    }
 
    template <class BidirectionalIterator, class Distance>
    void advance_dispatch(BidirectionalIterator& i, Distance n, 
       bidirectional_iterator_tag) {
      if (n >= 0)
        while (n--) ++i;
      else
        while (n++) --i;
    }
 
    template <class RandomAccessIterator, class Distance>
    void advance_dispatch(RandomAccessIterator& i, Distance n, 
       random_access_iterator_tag) {
      i += n;
    }
  }
 
  template <class InputIterator, class Distance>
  void advance(InputIterator& i, Distance n) {
    typename iterator_traits<InputIterator>::iterator_category category;
    detail::advance_dispatch(i, n, category);
  }
}
Добавлено через 2 минуты
в моем случае просто идет работа с view, т.е. быстродействие совсем не обязательно... можно экспериментировать со свистелками-перделками
DrOffset
6786 / 3997 / 917
Регистрация: 30.01.2014
Сообщений: 6,818
15.07.2016, 00:09     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #11
Цитата Сообщение от tapochka Посмотреть сообщение
можете плз на коленках набросок кинуть?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class CTest
    : public CTest_base
{
public:
    CTest() : a() {}
    ~CTest() noexcept {}
    //something else
    void set()
    {
        a(vec);
    }
    template <typename Actor>
    void set_a(Actor && ac)
    {
        a = std::move(ac);
    }
private:
    std::function<void(std::vector<int> &)> a;
};
Логика такая: если мы все равно задаем ключ операции внешним источником, то может быть сразу саму операцию и передавать извне?
tapochka
34 / 34 / 8
Регистрация: 25.04.2014
Сообщений: 449
15.07.2016, 00:21  [ТС]     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #12
Цитата Сообщение от DrOffset Посмотреть сообщение
Логика такая: если мы все равно задаем ключ операции внешним источником, то может быть сразу саму операцию и передавать извне?
слишком по-уродски получится... выражения трехэтажные получатся

спасибо, мысль понял... жаль только еще более элегантных решений нету...
DrOffset
6786 / 3997 / 917
Регистрация: 30.01.2014
Сообщений: 6,818
15.07.2016, 00:32     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #13
Ну или (если уж от интового ключа никак не избавиться) как-то так:
В принципе и без std::function можно обойтись.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class CTest
    : public CTest_base
{
public:
    CTest() : a() {}
    ~CTest() noexcept {}
    //something else
    void set()
    {
        a(vec);
    }
    void set_a(int key)
    {
        static void ( * op[])(std::vector<int> &) =
        {
             [](std::vector<int> & vec) {  vec.emplace_back(0); }
           , [](std::vector<int> & vec) {  vec.resize(5); }
           , [](std::vector<int> & vec) {  vec.clear(); }
           , [](std::vector<int> & vec) {  vec.shrink_to_fit(); }
        };
        a = op[key];
    }
 
private:
    void(* a)(std::vector<int> &);
};


Добавлено через 7 минут
Цитата Сообщение от tapochka Посмотреть сообщение
жаль только еще более элегантных решений нету
Да есть. Просто задача непонятная, допуски на задачу непонятные.
Универсального решения - да, нету. Но это всем известно.

Насчет:
Цитата Сообщение от tapochka Посмотреть сообщение
вот думал что-то типа tag-dispatching.
Посмотри-ка boost::variant и его static_visitor.
И вот сюда глянь: https://stackoverflow.com/questions/...late-functions
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.07.2016, 00:57     Какой паттерн подойдет, чтобы избежать длинных ветвлений?
Еще ссылки по теме:

Какой банк выбрать, чтобы выгодно обменять доллары на рубли C++ Builder
Какой компонент можно использовать, чтобы сделать такое как показано на скриншоте? C++ Builder
C++ Обеспечить пропуск расчетов, чтобы избежать деления на ноль
Visual C++ Какой проект нужно создать, чтобы приведенный код заработал?
Какой язык программирования лучше всего подойдет начинающему для взаимодействия с веб-сайтами? C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
tapochka
34 / 34 / 8
Регистрация: 25.04.2014
Сообщений: 449
15.07.2016, 00:57  [ТС]     Какой паттерн подойдет, чтобы избежать длинных ветвлений? #14
Цитата Сообщение от DrOffset Посмотреть сообщение
Посмотри-ка boost::variant и его static_visitor.
а ведь да... я ж чутка разбирался... спасибо что напомнили

Добавлено через 18 минут
вот по этой статье разбирался, может кому пригодится
[вырезано]
Yandex
Объявления
15.07.2016, 00:57     Какой паттерн подойдет, чтобы избежать длинных ветвлений?
Ответ Создать тему
Опции темы

Текущее время: 02:26. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru