Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Список функций класса. 
:(
    Опции темы
OlegIT
Дата 7.7.2014, 07:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 684
Регистрация: 5.4.2006

Репутация: нет
Всего: нет



В классе имеются несколько однотипных функций. Как сделать список из этих функций в QList или vector?

PM MAIL   Вверх
Lukkoye
Дата 7.7.2014, 08:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 86
Регистрация: 23.3.2013

Репутация: 1
Всего: 1



 http://rextester.com/XFBRA12764

Код

#include <vector>
#include <functional>
#include <iostream>
using namespace std;

#ifdef __MINGW__
    #define dFUNCTION __PRETTY_FUNCTION__
#endif

#ifdef __MINGW32__
    #define dFUNCTION __PRETTY_FUNCTION__
#endif

#ifdef __GNUC__
    #define dFUNCTION __PRETTY_FUNCTION__
#endif
    
#ifdef _MSC_VER
    #define dFUNCTION __FUNCSIG__
#endif

struct example1
{
    typedef void(example1::*func)();
    
    void foo() { cout << dFUNCTION<<endl; }
    void bar() { cout << dFUNCTION<<endl; }
    void baz() { cout << dFUNCTION<<endl; }
    
    example1()
    {
        mfunc.emplace_back( &example1::foo );
        mfunc.emplace_back( &example1::bar );
        mfunc.emplace_back( &example1::baz );
    }
    
    void launch()
    {
        for(auto& i: mfunc)
            (this->*i)();
    }
    
private:
    
    vector<func> mfunc;
    
};

struct example2
{
    typedef function<void()> func;
    
    void foo() { cout << dFUNCTION<<endl; }
    void bar() { cout << dFUNCTION<<endl; }
    void baz() { cout << dFUNCTION<<endl; }
    
    example2()
    {
        mfunc.emplace_back( bind(&example2::foo,this) );
        mfunc.emplace_back( bind(&example2::bar,this) );
        mfunc.emplace_back( bind(&example2::baz,this) );
    }
    
    void launch()
    {
        for(auto& i: mfunc)
            i();
    }
    
private:
    
    vector<func> mfunc;
    
};

int main()
{
    std::cout << "Hello, world!\n";
    
    example1 exa1; exa1.launch();
    std::cout << "-----------------------\n";
    example2 exa2; exa2.launch();
}


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

Второй способ более мощный, гибкий - создание делегата.

Делегат - это особый класс функторов (std::function), способный осуществлять запуск свободной функции или функции члена, без необходимости "помнить" к какому классу относится функция-член.

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


PM MAIL   Вверх
OlegIT
Дата 7.7.2014, 11:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 684
Регистрация: 5.4.2006

Репутация: нет
Всего: нет



Спасибо.

Как я понимаю Ваша ссылка на ресурс, где можно запускать свой код, вставляя его в окно редактора. Так?

Это сообщение отредактировал(а) OlegIT - 7.7.2014, 11:20
PM MAIL   Вверх
OlegIT
Дата 8.7.2014, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 684
Регистрация: 5.4.2006

Репутация: нет
Всего: нет



Протестировал Ваш код в Visual Studio и в Qt5.3. Ошибки такие, компилятор не знает, что есть такое emplace_back (хотя внутри vector он есть) и bind. И на функцию launch() по полной выругался. Поместил в буфер функции с помощью push_back, но вызвать их не получается.

У меня другой ещё вопрос. Это всё мне нужно для предотвращения зацикливания, мои однотипные функции могут вызываться последовательно и вернутся к первоначальной функции. Что бы этого избежать, я создаю буфер из этих функций, а потом, в основном цикле программы, выполняю вызов функций из этого буфера. Но при вызове может оказаться, что буфер функций пополнился. Не будет тут проблемы? Может по другому это можно сделать?

PM MAIL   Вверх
NoviceF
Дата 8.7.2014, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Цитата(OlegIT @  8.7.2014,  12:14 Найти цитируемый пост)
Протестировал Ваш код в Visual Studio и в Qt5.3. Ошибки такие, компилятор не знает, что есть такое emplace_back

В qt включал c++11 в pro файле? Что-то в таком духе
Код

QMAKE_CXXFLAGS += -std=c++0x

PM MAIL   Вверх
OlegIT
Дата 8.7.2014, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 684
Регистрация: 5.4.2006

Репутация: нет
Всего: нет



Цитата(NoviceF @  8.7.2014,  13:03 Найти цитируемый пост)
В qt включал c++11 в pro файле? Что-то в таком духе

Включу.

Мне не очень нравится моя идея по защите, тут ещё вопрос как/где запустить отработку созданного буфера. Может есть другие, более грамотные решения?
PM MAIL   Вверх
NoviceF
Дата 8.7.2014, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Цитата(OlegIT @  8.7.2014,  15:24 Найти цитируемый пост)
тут ещё вопрос как/где запустить отработку созданного буфера

Это вопрос из области многопоточности. В случае если к структуре данных имеют доступ два и более потоков, нужно синхронизировать доступ к ней при помощи примитивов синхронизации, таких как мьютексы, rwlock, и т.п.

То есть, перед тем, как ты начинаешь вызывать функции коллекции, ты захватываешь мьютекс, и ни один другой поток не сможет получить доступ к этой коллекции, пока ты мьютекс не освободишь. Все потоки, что будут пытаться внести изменения в коллекцию или выполнить чтение из неё, будут блокироваться на вызове функции захвата мьютекса, и разблокируются (по одному) только тогда, когда поток, совершающий обход коллекции мьютекс освободит.
PM MAIL   Вверх
Lukkoye
Дата 8.7.2014, 19:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 86
Регистрация: 23.3.2013

Репутация: 1
Всего: 1



Цитата(OlegIT @  8.7.2014,  11:14 Найти цитируемый пост)
Протестировал Ваш код в Visual Studio и в Qt5.3. Ошибки такие, компилятор не знает, что есть такое emplace_back (хотя внутри vector он есть) и bind. И на функцию launch() по полной выругался. Поместил в буфер функции с помощью push_back, но вызвать их не получается.


Вижал студия из коробки умеет std::function начиная с версии 10

Насчет Qt:

1. Если вы используете систему сборки QMake, пропишите в файле сценария сборки  имя_вашего_проекта.pro следующий ключ:

QMAKE_CXXFLAGS += -std=gnu++1y
либо 
QMAKE_CXXFLAGS += -std=c++0x


1. Если вы используете систему сборки Сmake, пропишите в файле сценария сборки CMakeLists.txt
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++1y ")
либо 
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")

Данный ключ активирует поддержку нововведений в стандарте языка.

По поводу "зацикливаний":


Цитата(OlegIT @  8.7.2014,  11:14 Найти цитируемый пост)
Но при вызове может оказаться, что буфер функций пополнился. Не будет тут проблемы? Может по другому это можно сделать?


Разумеется будут.

Каноничную реализацию можно подглядеть рассматривая устройство какой нибудь "EventSystem".

Если вкратце: есть отдельный класс, называемый "Eventsystem ", который хранит внутри себя несколько списков:
1. Желающие добавиться.
2. Желающие удалиться. Этот список представляет собой пару: <делегат, вкл/выкл>

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

Допустим, запуск делегата приводит в действие функцию, которая пытается добавить в Eventsystem новый делегат - он добавляется в список "желающих добавиться". Рабочий же список остается без изменений.

Если же запуск делегата приводит в действие функцию, которая напротив, пытается удалить делегат - он просто помечается как "выкл", и Eventsystem знает, что его использовать нельзя. Больше он уже не будет запущен.
Если же претендент на удаление обнаружится в списке "желающих добавиться" - можно удалить оттуда сразу же.

После того, как весь рабочий цикл завершился, только тогда Eventsystem добавляет в рабочий список новеньких, а так же выбрасывает всех тех, кто помечен, как "выкл".

Кроме того, поскольку запуски делегатов происходят в одном единственном месте: в Eventsystem, там удобно ставить защиту для многопоточного режима, а так же легко пропасти - был ли один и тот же делегат вызван дважды.

То бишь, легко отловить факт рекурсивных вызовов, и зацикливания.



Это сообщение отредактировал(а) Lukkoye - 8.7.2014, 19:26
PM MAIL   Вверх
OlegIT
Дата 9.7.2014, 11:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 684
Регистрация: 5.4.2006

Репутация: нет
Всего: нет



Спасибо за разъяснения. С делегатами и двумя очередями понятно. Не понятно где выполнять вызовы, обработку списка и где "Eventsystem добавляет в рабочий список новеньких"?


Это сообщение отредактировал(а) OlegIT - 9.7.2014, 13:41
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1109 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.