尝试使用>>创建新的eventHandler重载运算符,迷失了自己试图弄清楚所需的语法

时间:2012-01-21 22:59:47

标签: c++ templates functor

编辑,澄清: * 我希望能够使用我自己的类EventListener使用重载的运算符>>设置eventHandlers,我无法弄清楚它的语法 *

问题是重载的>>=运算符与参数化的eventHandler不匹配,我不知道如何正确声明它!

OR

如果我匹配,将通用T类型转换为体面有用的eventHandler对象所需的信息是消失 !!我需要一个混合语法来声明泛型类型T和第二个泛型类型作为参数。

使用eventHandler类的父级,efunctor也没用,因为它没有参数化。

示例:

链接>>新的eventHandler(& App :: testFunction,app); /*where app is an istance of App class and testFunction is a method of App. */

我有一个名为eventHandler的课程,其格式为eventHandler<class T>。现在,我想重载一些类的>>运算符,以允许我像这样使用它:

link >> new eventHandler(&App::testFunction, App);

其中App是另一个类,而testFunction显然是该类的一个方法。写入的行应该具有对链接类的>>=运算符的调用(方便地称为Link)。

我会发布部分代码以使其更清晰:

class Link
{
public:
    eventListener* EventListener;
    Link()
    {
        this->EventListener = new eventListener();
    }   

    // PROBLEM
    // I am lost here, tried different syntaxes but with no success
    //template<template<class G> class T, class F> 

    template <class T>
    Link operator>>=(T& ev)
    { 
        cout << "something";
         // Here there is no way to declare the proper eventHandler
        eventHandler<?>* event = (eventHandler<?>)ev;
         // I need something like T<F> 
        event->eventName = 'onTest';
        this->eventListener->add(event);
        return *this; 
} 

};

template<class T, class F> 
T operator>>(T& lhs, F& rhs)
{ 
    return T(lhs)>>=rhs;
} 

class App
{
public:
    void testFunction(e evt)
    {
        cout << "it works!" << "\n";
    }
};

int main()
{
    App* app = new App;
    Link* link = new link;
    Link link1;

    eventHandler<App>* ev = new eventHandler<App>(app, &App::testFunction);
    link1 >> ev;    

    // this line should echo "it works!"
    link1.EventListener->triggerEvent("onTest");

    // PART 2
    // HOW CAN I USE?
    // link >> ev; 
    // when link is a Link*

    return 0;
}

我的问题是如何从Link声明方法operator>>=,以便自动启用我的那种功能。

澄清: - 我希望能够使用Link类上的>>运算符向EventListener类添加一个新的eventHandler,该运算符具有右手操作数和实际的eventHandler;

编辑1:

我还有第二个问题: 如何声明>>重载函数,以便使用指向Link类的指针调用...这意味着如果我想使用link而不是>>,我该怎么办? {1}}。

对PART2的回答:我的猜测是我必须取消引用指针才能使用运算符重载。

另一个编辑

这是代码的一个版本,可能会更好地解释它。我的问题是编译器失败的地方,在Link类中匹配link1运算符,如果正确解决它可能会起作用,问题是我找不到如何匹配它并保留事件签名。

现在,我最好让代码说明一切:

>>=

我还会发布我的活动定义:

#include <iostream>
#include <stdio.h>
#include "events/events.h"
using namespace std;

class Link
{
public:
    eventListener* EventListener;

public:
    Link()
    {
        this->EventListener = new eventListener();
    }   

    template<class T>
    Link operator>>=(const T& ev)
    { 
        ev->eventName = "onReceive";
        this->EventListener->add(ev);
        return *this; 
    }
};

template<class T, class F> 
T operator>>(T& lhs, const F& rhs)
{ 
    return T(lhs)<<=rhs;
} 

class App
{
public:
    void testReceive(e evt)
    {
        cout << "it works" << "\n" << evt.value;
    }

};

class demo
{
public:
    Link* parent;
    void testit(char* msg)
    {
        parent->EventListener->triggerEvent("onReceive", this, msg);
    }
};

int main()
{
    App* app = new App;
    Link link;

    eventHandler<App>* ev = new eventHandler<App>(app, &App::testReceive);
    link >> ev; 

    demo d;
    d.parent = &link;
    // should output "it works!"
    d.testit("here");

    return 0;
}

2 个答案:

答案 0 :(得分:1)

除了过度使用new之外,在尝试这样的事情之前,还有其他一些我认为你需要在概念上清楚的东西。如果有必要,重载operator>>()以调用operator>>=()的合适成员版本并没有任何问题,尽管它甚至可能不需要这样做:如果您控制移位运算符的左手参数,如果你愿意,你可以把它变成一个成员。它只是不能用std::istream这种方式工作,因为你无法控制标准的C ++库类[模板]。

在继续之前,让我们回答您首先添加的问题:您不能重载任何仅涉及内置类型的运算符。指针被认为是内置类型。故事结局。你应该使用指针:它们是某些地方你需要的低级抽象,但是你想要处理更高级别的适当类的对象。这并不会使事情变得更加困难,但它会使事情变得更容易。

在你的代码中,突然出现了一些模板模板:这几乎肯定不是必需的,而是你问题的一部分。此外,如果您希望事件接收器具有某种多态性,您将需要一个小的继承层次结构:您将定义一个基类,它公开接口用于触发事件和一个模板化的派生类,它实现了一些虚函数由此接口定义。当一个事件被调用时,base只调用虚函数,偶数就会接收它。这就是std::function<Signature>有效运作的方式。

我认为你的问题中有太多未定义的东西要用一个有效实现你想要的代码示例来回答它。就个人而言,我会遵循std::function<>的模型并定义一个事件模板,该事件模板将事件的签名作为参数和函数对象触发,并将相应的签名作为接收者。也就是说,您订阅的事件如下所示:

event<void(std::string)> onTest;

如果你想添加一个具有要在其上调用的特定成员的对象,你会做一些事情,这是一个常见的用例,你可以创建一个EventHandler类模板来使用它有效地做

的内容
onTest >> std::bind(std::mem_fn(&App::testFunction), std::ref(app), _1);

(这只是使用std::bind()来简洁;如果你想支持具有固定数量参数的函数,这很容易实现,假设你不能使用std::bind()boost::bind()我想重新实现bind():这是一个相当毛茸茸的事情。)

这是一个完整且有效的例子,我认为它显示了所有的成分(并且尽可能接近我认为你想要的那样):

#include <iostream>
#include <memory>
#include <algorithm>
#include <vector>

struct event_base
{
    virtual ~event_base() {}
    virtual void call(std::string const&) = 0;
};

template <typename T>
struct event: event_base
{
    event(T* o, void (T::*m)(std::string const&)):
        object(o),
        member(m)
    {
    }

private:
    void call(std::string const& arg) {
        (this->object->*member)(arg);
    }
    T*   object;
    void (T::*member)(std::string const&);
};


template <typename T>
event_base* make_event(T* object, void (T::*member)(std::string const&)) {
    return new event<T>(object, member);
}

class event_listener
{
public:
    ~event_listener() { std::for_each(events.begin(), events.end(), &deleter); }
    void add(event_base* event) { this->events.push_back(event); }
    void trigger(std::string const& argument) const {
        for (std::vector<event_base*>::const_iterator it(events.begin()), end(events.end());
             it != end; ++it) {
            (*it)->call(argument);
        }
    }

private:
    static void deleter(event_base* ptr) { delete ptr; }
    std::vector<event_base*> events;
};

class Link
{
public:
    event_listener listener;
    void operator>>= (event_base* ev) { this->listener.add(ev); }
};

void operator<< (Link& link, event_base* ev) {
    link >>= ev;
}

class App
{
public:
    void onTest(std::string const& arg) { std::cout << "App::onTest(" << arg << ")\n"; }
};

int main()
{
    std::auto_ptr<Link> link(new Link);
    std::auto_ptr<App>  app(new App);

    *link << make_event(app.get(), &App::onTest);
    link->listener.trigger("hello event");
}

注意,有明显的扩展,例如使参数类型成为模板参数。这相当于在不同的地方添加这个模板参数,但整体方法保持不变。

答案 1 :(得分:1)

我的猜测是,您需要让eventHandler<T>来自eventHandlerBase这样的类,这样您就可以参考任何类型的eventHandler<T> TeventHandlerBase指向Link::EventListener的指针...即eventHandlerBase * delcared为类型template<typename T> const link &operator>>=(const eventHandler<T>& ev) { ev->eventName = "onTest"; this->EventListener = &ev; }

然后这样的事情可能有效:

new

Link::EventListener内没有Link()的{​​{1}}声明。)