c ++ Покажчик функціональних елементів

Я прочитав кілька повідомлень про це, але, здається, не може точно знайти те, що шукаю, з прикладом коду, якщо хтось може дати мені якусь допомогу, яку я би дуже цінував.

у моєму заголовку я маю:

void addEvent(void (*func)(Pack  *));

void triggerEvents(Pack * );

std::list eventList;

і в файлі cpp

void DNetwork::addEvent(void (*func)(Pack *)){
    eventList.push_back(func);
}

void DNetwork::triggerEvents(Pack * pack){
    for (std::list::iterator it = eventList.begin(); it !=         eventList.end() ;it++ ){
        (*it)(pack);
    } 
}

Це чудово працює з безкоштовними функціями, але коли я намагаюся додати функцію-члену до цього списку, я отримую помилку. Хто-небудь знає, як зберігати функцію-члена (з об'єктів довільного класу) всередині покажчика?

1
Див. Розділ "Часті питання C ++" 33: parashift.com/c++-faq/pointers- to-members.html
додано Автор aschepler, джерело
Див. Розділ "Часті питання C ++" 33: parashift.com/c++-faq/pointers- to-members.html
додано Автор aschepler, джерело
додано Автор kfsone, джерело
додано Автор kfsone, джерело
Подивіться на std :: function
додано Автор Jiwan, джерело
Подивіться на std :: function
додано Автор Jiwan, джерело
Yap: ReturnType (TheClass :: * memberPointer) (аргументи, ...) = & TheClass :: aMemberFunction;
додано Автор user529758, джерело
Так, але я хочу мати можливість зберігати функціональні покажчики з різних класів. Чи можливо мати батьківський клас для класу, який я хочу використовувати, який може виконувати функції, щоб список був таким: щось на зразок цього std :: list eventList;
додано Автор dag roger stokland rui, джерело
Так, але я хочу мати можливість зберігати функціональні покажчики з різних класів. Чи можливо мати батьківський клас для класу, який я хочу використовувати, який може виконувати функції, щоб список був таким: щось на зразок цього std :: list eventList;
додано Автор dag roger stokland rui, джерело

7 Відповіді

The simple solution is using type erasure on the function/function pointer type, for which the easier way is just using std::function<>:

std::list;

Потім ви можете ініціалізувати об'єкти function або вільною функцією, або функцією-членом (за допомогою std :: bind , щоб пов'язати функцію-члену з об'єктом, на якому назвемо це) або навіть об'єкти функції (типи, які пропонують operator() ).

3
додано

The simple solution is using type erasure on the function/function pointer type, for which the easier way is just using std::function<>:

std::list;

Потім ви можете ініціалізувати об'єкти function або вільною функцією, або функцією-членом (за допомогою std :: bind , щоб пов'язати функцію-члену з об'єктом, на якому назвемо це) або навіть об'єкти функції (типи, які пропонують operator() ).

3
додано

Якщо я розумію вашу проблему, ви отримаєте помилку, коли ви спробуєте додати функцію до списку в addEvent?

Якщо ви додаєте вказівник на функцію члена нестатичної класу, переконайтеся, що він має правильний синтаксис ... наприклад, покажчик функції на член-функцію в TestClass виглядає так:

void * (TestClass:: *) ()
2
додано
Це не вирішить проблему. Нам потрібен просто спосіб пов'язувати звичайну функцію та метод. Так це функція juast + bind
додано Автор elvis.dukaj, джерело

Якщо я розумію вашу проблему, ви отримаєте помилку, коли ви спробуєте додати функцію до списку в addEvent?

Якщо ви додаєте вказівник на функцію члена нестатичної класу, переконайтеся, що він має правильний синтаксис ... наприклад, покажчик функції на член-функцію в TestClass виглядає так:

void * (TestClass:: *) ()
2
додано
Це не вирішить проблему. Нам потрібен просто спосіб пов'язувати звичайну функцію та метод. Так це функція juast + bind
додано Автор elvis.dukaj, джерело

Для функції-члена потрібен зв'язок. Функція-член - "нормальна функція", яка має неявний параметр свого класу. Отже, вам потрібен зв'язувальний матеріал. Якщо ви використовуєте c ++ 11, ви можете скористатися функцією std :: bind і std ::, або ви можете використовувати функцію boost :: bind and boost :: для не c ++ 11 коду.

typedef std::function< void ( Pack* ) > MyFunction;
void addEvent( MyFunction f );
void triggerEvents( Pack* );
std::list< MyFunction > eventList;

void DNetwork::addEvent( MyFunction f )
{
    eventList.push_back( f );
}

void DNetwork::triggerEvents( Pack *pack )
{
    for ( auto it = eventList.begin(); it != eventList.end(); it++ )
    {
        (*it)(pack);
    } 
}

Тепер, якщо у мене є клас А з методом doA (Pack *) , я напишу:

A a;
Pack pack;
DNetwork d;
d.addEvent( std::bind( &A::doA, &a, &pack ) );

Or even better you can use Boost.Signal or you can use the Publisher/Subcriber Pattern

Edit As @DavidRodríguez-dribeas suggest: The bind should not take the &pack argument, as the argument to the member function is provided at the place of call in triggerEvents. The correct way is:

A a;
Pack pack;
DNetwork d;
d.addEvent( std::bind( &A::doA, &a, std::placeholders::_1 ) );
d.triggerEvents( &pack );
1
додано
@ DavidRodríguez-dribeas Ви маєте рацію. Це повинно бути d.addEvent (std :: bind (& A :: doA, & a, std :: placeholders :: _ 1));
додано Автор elvis.dukaj, джерело
Прив'язка не повинна приймати аргумент & pack , оскільки аргумент функції-члену забезпечується в місці виклику в triggerEvents
додано Автор David Rodríguez - dribeas, джерело

Для функції-члена потрібен зв'язок. Функція-член - "нормальна функція", яка має неявний параметр свого класу. Отже, вам потрібен зв'язувальний матеріал. Якщо ви використовуєте c ++ 11, ви можете скористатися функцією std :: bind і std ::, або ви можете використовувати функцію boost :: bind and boost :: для не c ++ 11 коду.

typedef std::function< void ( Pack* ) > MyFunction;
void addEvent( MyFunction f );
void triggerEvents( Pack* );
std::list< MyFunction > eventList;

void DNetwork::addEvent( MyFunction f )
{
    eventList.push_back( f );
}

void DNetwork::triggerEvents( Pack *pack )
{
    for ( auto it = eventList.begin(); it != eventList.end(); it++ )
    {
        (*it)(pack);
    } 
}

Тепер, якщо у мене є клас А з методом doA (Pack *) , я напишу:

A a;
Pack pack;
DNetwork d;
d.addEvent( std::bind( &A::doA, &a, &pack ) );

Or even better you can use Boost.Signal or you can use the Publisher/Subcriber Pattern

Edit As @DavidRodríguez-dribeas suggest: The bind should not take the &pack argument, as the argument to the member function is provided at the place of call in triggerEvents. The correct way is:

A a;
Pack pack;
DNetwork d;
d.addEvent( std::bind( &A::doA, &a, std::placeholders::_1 ) );
d.triggerEvents( &pack );
1
додано
@ DavidRodríguez-dribeas Ви маєте рацію. Це повинно бути d.addEvent (std :: bind (& A :: doA, & a, std :: placeholders :: _ 1));
додано Автор elvis.dukaj, джерело
Прив'язка не повинна приймати аргумент & pack , оскільки аргумент функції-члену забезпечується в місці виклику в triggerEvents
додано Автор David Rodríguez - dribeas, джерело

Ви можете зробити перевантаження, наприклад:

std::list eventList;
void addEvent(void (*func)(Pack  *));
template
void addEvent(void (T::*func)(Pack  *));
namespace Abstraction {
    template
    void abstractlyAddEvent( T, std::list *eventList );
}
1
додано
не треба ускладнювати речі так багато! просто зв'яжіться!
додано Автор elvis.dukaj, джерело
@ elvis.dukaj Не потрібно позначати мене, моє рішення працює так само добре. :-(
додано Автор The Floating Brain, джерело
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147