Использование async с полиморфной функцией-членом

Попытка создать шаблон асинхронного наблюдателя вызывает ошибку компилятора C3867, и я не знаю, как ее решить. Пример кода выглядит следующим образом

class Subject;

class Observer
{
public:
virtual void notify(Subject* s) = 0;
virtual ~Observer() {};
};

class Subject
{
std::map<std::string, Observer *> observers;
protected:
void notify_observers()
{
std::map<std::string, Observer *>::iterator iter;
for (iter = observers.begin(); iter != observers.end(); ++iter) {
void (Observer::*notify)(Subject *) = iter->second->notify;
std::async(std::launch::async, notify, this);
}
}

public:
virtual ~Subject() {};
void observer(std::string id, Observer* o)
{
observers[id] = o;
}
};

template<typename Iter, typename type>
class Sort : public Observer {
public:
virtual void notify(Subject* s)
{
TestSort<Iter> *a;
a = dynamic_cast<TestSort<Iter> *>(s);
std::vector<type> temp(a->beg(), a->end());

sort(temp->beg(), temp->end());
}
};

template<typename Iter, typename type>
class InsertionSort : public Sort<Iter, type>
{
void sort(Iter beg, Iter end) {
for (Iter i = beg; i != end; ++i)
std::rotate(std::upper_bound(beg, i, *i), i, i+1);
}};
int main ()
{
std::vector<double> data(100);
std::generate(data.begin(), data.end(), [](){return rand() % 500;} );
auto ts = TestSort<std::vector<double>::iterator >(data.begin(), data.end());

auto is = new InsertionSort<std::vector<double>::iterator, double >();
//.................
ts.observer("InsertionSort", is);
//.........................
ts.Triggerd();
return 0;
}

Хотя я понимаю ошибку

 error C3867: 'Observer::notify': function call missing argument list; use '&Observer::notify' to create a pointer to member

И все же в этом контексте я не могу понять, как ее решить.

В этом контексте, если бы уведомление было бы просто доступной функцией-членом, вместо

void (Observer::*notify)(Subject *) = iter->second->notify;

Я мог бы просто написать

void (Observer::*notify)(Subject *) = &Observer::notify;

Но notify — это полиморфная функция, и я не могу обратиться к нужной функции во время компиляции.

Подскажите пожалуйста как мне обработать

1

Решение

Изменить:

void (Observer::*notify)(Subject *) = iter->second->notify;
std::async(std::launch::async, notify, this);

Для того, чтобы:

void (Observer::*notify)(Subject *) = &Observer::notify;
std::async(std::launch::async, std::mem_fun(notify), iter->second, this);

Когда вы вызываете метод, вам нужны и указатель на экземпляр, и аргументы. Стандартный синтаксис rettype retval = instance->method(arg);, но std::mem_fun вернет функтор, который вы можете использовать как rettype retval = std::mem_fun(&InstanceType::method)(instance, arg); — это делает неявное this указатель передается функции-члену в явном виде.

От указателя к virtual метод, плюс указатель на объект, std::mem_fun можно выяснить, какой экземпляр virtual метод, который вы должны вызвать.

Подобную вещь можно сделать с bind или лямбда. Вот примерно эквивалентный вызов с использованием лямбда-синтаксиса:

 Observer* observer = iter->second;
std::async(std::launch::async, [observer,this]() { observer->notify(this); } );

Смотрите комментарий ниже: вам не нужно использовать std::mem_fun, async сделаю это для вас. Вы должны передать указатель экземпляра функции-члена в качестве следующего аргумента.

1

Другие решения

Вам не нужно выяснять правильную функцию во время компиляции, так же как вам не нужно выяснять это для обычного вызова виртуальной функции. Просто используйте &Observer::notify, Правильная функция выбрана во время вызов, не в момент взятия его адреса.

4

По вопросам рекламы [email protected]