尝试使用重载运算符创建新的事件处理程序>>迷失了自己试图找出所需的语法
Trying to create a new eventHandler using >> overloaded operator, lost myself trying to figure out the required syntax
编辑,澄清:*我希望能够使用重载运算符>>
使用我自己的类 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::EventListener
的new
语句。
- 没有为自己的结构调用列表推回方法
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- EASTL矢量<向量<int>>连续的
- 在c++中为我自己的基于指针的数组分配内存的正确方法
- C++从对象自己的类中删除对象
- 使用 std::optional,而不是自己的结构
- 子轴围绕父轴而不是他自己的轴旋转
- 有没有办法让类在C++中转换自己
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- C++ 如何为自己的迭代器类从迭代器转换为const_iterator?
- 重载 + 自己的类和 std::string 的运算符
- 类无法访问自己的私有静态 constexpr 方法 - Clang bug?
- 是否可以在不填充自己的参数的情况下将模板函数作为参数传递?
- 如何访问模板参数自己的模板参数?
- 将矩阵乘以我自己的输入的向量
- 您应该在什么时候创建自己的异常类型
- 派生类是从基类继承 v 指针并仅使用它,还是也有自己的 v 指针?
- string1 == string2 和你自己的 for 循环比较有什么区别?
- 如何正确包含我自己的标头?