Вызовите любую функцию-член объекта в списке объектов, используя std::function

У меня есть список объектов, где мне нужно вызвать функцию-член — пока ничего особенного: перебрать список, сделать этот вызов — готово.

Теперь у меня есть несколько мест, которые делают почти то же самое в одном и том же списке, за исключением того, что вызываемая функция-член меняется (аргумент всегда один и тот же, двойное значение).

Я немного пробовал с std::function, но в итоге не смог заставить его работать. Какие-либо предложения? (Я вернулся к С++ после многих лет работы с С#, так что многое забыл).

Вот как это выглядит сейчас:

void CMyService::DoSomeListThingy(double myValue)
{
    for (std::list<CMyListItem*>::iterator v_Iter = myList.begin(); v_Iter != myList.end(); ++v_Iter)
    {
        (*v_Iter)->MethodToBeCalled(myValue);
    }
}

void CMyService::DoSomeThingDifferent(double myValue)
{
    for (std::list<CMyListItem*>::iterator v_Iter = myList.begin(); v_Iter != myList.end(); ++v_Iter)
    {
        (*v_Iter)->CallTheOtherMethod(myValue);
    }
}

И вот как я бы предпочел:

void CMyService::DoSomeListThingy(double myValue)
{
    ApplyToList(&CMyListItem::MethodToBeCalled, myValue);
}

void CMyService::DoSomeThingDifferent(double myValue)
{
    ApplyToList(&CMyListItem::CallTheOtherMethod, myValue);
}

void CMyService::ApplyToList(std::function<void(double)> func, double myValue)
{
    for (std::list<CMyListItem*>::iterator v_Iter = myList.begin(); v_Iter != myList.end(); ++v_Iter)
    {
        (*v_Iter)->func(myValue);
    }
}

person Robin Holenweger    schedule 22.12.2017    source источник


Ответы (2)


void CMyService::ApplyToList(void (CMyListItem::*func)(double), double myValue) {
    for (auto p : myList) {
        (p->*func)(myValue);
    }
}

С компиляторами до C++11:

void CMyService::ApplyToList(void (CMyListItem::*func)(double), double myValue) {
  for (std::list<CMyListItem*>::iterator v_Iter = myList.begin();
       v_Iter != myList.end(); ++v_Iter) {
    ((*v_Iter)->*func)(myValue);
  }
}
person Igor Tandetnik    schedule 22.12.2017
comment
Выглядит очень просто, хотя есть проблемы с его использованием с VS2010; может он не поддерживается? - person Robin Holenweger; 22.12.2017
comment
Добавлен вариант, в котором не используются какие-либо функции C++11. - person Igor Tandetnik; 22.12.2017
comment
На самом деле я думаю, что диапазон, основанный на цикле for, появился только после VS2010. См. ‹stackoverflow.com/questions/6898859/ - person Robin Holenweger; 22.12.2017

Вы можете использовать lambdas

void CMyService::ApplyToList(std::function<void(CMyListItem*, double)> func, double myValue))
{
    for (std::list<CMyListItem*>::iterator v_Iter = myList.begin(); v_Iter != myList.end(); ++v_Iter)
    {
        func(*v_Iter, myValue);
    }
}

а также

double val;
std::function<void(A*,double)> fun1 = [=](A *th,double) {
                                                  th->foo(val);
                                                 };

std::function<void(A*,double)> fun2 = [=](A *th,double) {
                                                  th->bar(val);
                                                 };
ApplyToList(fun1, val);
ApplyToList(fun2, val);
person Gaurav Sehgal    schedule 22.12.2017