1

尝试创建异步观察者模式会导致编译器错误 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

然而在这种情况下,我无法弄清楚如何解决它。

在这种情况下,如果 notify 将是一个简单的可添加成员函数,而不是

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

我本可以简单地写

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

但是 notify 是一个多态函数,我无法在编译时处理正确的函数。

请建议我应该如何处理

4

2 回答 2

4

您无需在编译时找出正确的函数,就像您不必为常规的虚函数调用找出正确的函数一样。只需使用&Observer::notify. 正确的函数是在调用时选择的,而不是在获取其地址时。

于 2012-12-18T18:08:01.453 回答
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

类似的事情可以用 abind或 lambda 来完成。这是使用 lambda 语法的大致等效调用:

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

请参阅下面的评论:您不必使用std::mem_funasync会为您使用。您仍然必须将成员函数的实例指针作为下一个参数传递。

于 2012-12-18T18:49:36.753 回答