Попытка создать шаблон асинхронного наблюдателя вызывает ошибку компилятора 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 — это полиморфная функция, и я не могу обратиться к нужной функции во время компиляции.
Подскажите пожалуйста как мне обработать
Изменить:
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
сделаю это для вас. Вы должны передать указатель экземпляра функции-члена в качестве следующего аргумента.
Вам не нужно выяснять правильную функцию во время компиляции, так же как вам не нужно выяснять это для обычного вызова виртуальной функции. Просто используйте &Observer::notify
, Правильная функция выбрана во время вызов, не в момент взятия его адреса.