尝试使用重载运算符创建新的事件处理程序>>迷失了自己试图找出所需的语法

Trying to create a new eventHandler using >> overloaded operator, lost myself trying to figure out the required syntax

本文关键字:gt 自己 语法 迷失 重载 创建 事件处理 程序 运算符      更新时间:2023-10-16

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

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

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

并且使用 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 显然是该类的方法。写成 abose 的行应该具有对链接类的>>=运算符的调用(方便地称为 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 类中,该运算符具有右操作数和实际的事件处理程序;

编辑 1:

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

回答 PART2:我的猜测是我只需要取消引用指针即可使用运算符重载。

另一个编辑

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

现在,我最好让代码自己说话:

#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;
}

我还将发布我的事件定义:

#ifndef EVENTS_H
#define EVENTS_H
#include <stdio.h>
#include <string.h>
#include "clist.h"
#include <string>
enum scope {global = 0, scoped};
struct e
{
    void* target;
    void* value;
};
class efunctor //abstract
{
public:
    std::string eventname;
    virtual void operator()(e evt)
    { }
    virtual void Call(e evt)
    { }
};
template <class T>
class eventHandler : public efunctor
{
private:
    T* scope;
    void (T::*eventMethod)(e);
public:
    std::string name;
    std::string eventname;
    eventHandler(std::string eventnam, T* objscope,  void(T::*func)(e)) 
    { 
        this->scope = objscope;
        this->eventMethod = func;
        this->eventname = eventnam;
    }
    eventHandler(T* objscope,  void(T::*func)(e)) 
    { 
        this->scope = objscope;
        this->eventMethod = func;
    }
    eventHandler(void(T::*func)(e)) 
    {
        this->eventMethod = func;
    }
    void operator()(e evt)
    {
        (scope->*eventMethod)(evt);
    }          
    void Call(e evt)
    { 
        (scope->*eventMethod)(evt);
    }
};
class eventListener
{
private:
    clist< clist<efunctor* > > methods;
public:
    template <class T>
    void add(T other)
    {
        other->name = ToString(this->methods[other->eventname].length());
        methods[other->eventname][methods[other->eventname].length()] = other;
    }
    template <class T>
    void remove(T other)
    {
        methods[other->eventname]->remove(other->name);
    }
    template <class F>
    void triggerEvent(std::string name, void* target, F result)
    {
        e evt;
        evt.target = target;
        evt.value = (char*)result;
        for(methods[name].iterateStart(); 
                    !methods[name].eoi(); 
                    methods[name].next())
        {
            (*(methods[name].getCurrentIteration()))(evt);
        }
    }
};
#endif

除了过度使用new之外,我认为在尝试这样的事情之前,您需要在概念上弄清楚其他事情。重载operator>>()在必要时调用合适的operator>>=()成员版本实际上没有任何问题,尽管甚至可能没有必要这样做:如果您控制 shift 运算符的左手参数,您可以根据需要将其设置为成员。它只是不能以这种方式与std::istream一起使用,因为您无法控制库类 [template] 的标准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");
}

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

我的猜测是,您需要使eventHandler<T>派生自eventHandlerBase这样的类,以便您可以通过指向eventHandlerBase的指针来引用任何类型的eventHandler<T> T...即 Link::EventListener被描述为eventHandlerBase *型。

那么这样的事情可能会起作用:

template<typename T>
const link &operator>>=(const eventHandler<T>& ev)
{ 
    ev->eventName = "onTest";
    this->EventListener = &ev;
}

(并且没有Link()Link::EventListenernew语句。