因为我喜欢用 C# 和 C++ 编程,所以我打算实现一个类似 C# 的事件系统,作为我计划的 C++ SFML-GUI 的坚实基础。
这只是我的代码的摘录,我希望这能澄清我的概念:
// Event.h
// STL headers:
#include <functional>
#include <type_traits>
#include <iostream>
// boost headers:
#include <boost/signals/trackable.hpp>
#include <boost/signal.hpp>
namespace Utils
{
namespace Gui
{
#define IMPLEMENTS_EVENT(EVENTNAME, EVENTARGS) public: \
Utils::Gui::IEvent<EVENTARGS>& EVENTNAME() { return m_on##EVENTNAME; } \
protected: \
virtual void On##EVENTNAME(EVENTARGS& e) { m_on##EVENTNAME(this, e); } \
private: \
Utils::Gui::Event<EVENTARGS> m_on##EVENTNAME;
#define MAKE_EVENTFIRING_CLASS(EVENTNAME, EVENTARGS) class Fires##EVENTNAME##Event \
{ \
IMPLEMENTS_EVENT(EVENTNAME, EVENTARGS); \
};
class EventArgs
{
public:
static EventArgs Empty;
};
EventArgs EventArgs::Empty = EventArgs();
template<class TEventArgs>
class EventHandler : public std::function<void (void*, TEventArgs&)>
{
static_assert(std::is_base_of<EventArgs, TEventArgs>::value,
"EventHandler must be instantiated with a TEventArgs template paramater type deriving from EventArgs.");
public:
typedef void Signature(void*, TEventArgs&);
typedef void (*HandlerPtr)(void*, TEventArgs&);
EventHandler() : std::function<Signature>() { }
template<class TContravariantEventArgs>
EventHandler(const EventHandler<TContravariantEventArgs>& rhs)
: std::function<Signature>(reinterpret_cast<HandlerPtr>(*rhs.target<EventHandler<TContravariantEventArgs>::HandlerPtr>()))
{
static_assert(std::is_base_of<TContravariantEventArgs, TEventArgs>::value,
"The eventHandler instance to copy does not suffice the rules of contravariance.");
}
template<class F>
EventHandler(F f) : std::function<Signature>(f) { }
template<class F, class Allocator>
EventHandler(F f, Allocator alloc) : std::function<Signature>(f, alloc) { }
};
template<class TEventArgs>
class IEvent
{
public:
typedef boost::signal<void (void*, TEventArgs&)> SignalType;
void operator+= (const EventHandler<TEventArgs>& eventHandler)
{
Subscribe(eventHandler);
}
void operator-= (const EventHandler<TEventArgs>& eventHandler)
{
Unsubscribe(eventHandler);
}
virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler) = 0;
virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler, int group) = 0;
virtual void Unsubscribe(const EventHandler<TEventArgs>& eventHandler) = 0;
};
template<class TEventArgs>
class Event : public IEvent<TEventArgs>
{
public:
virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler)
{
m_signal.connect(*eventHandler.target<EventHandler<TEventArgs>::HandlerPtr>());
}
virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler, int group)
{
m_signal.connect(group, *eventHandler.target<EventHandler<TEventArgs>::HandlerPtr>());
}
virtual void Unsubscribe(const EventHandler<TEventArgs>& eventHandler)
{
m_signal.disconnect(*eventHandler.target<EventHandler<TEventArgs>::HandlerPtr>());
}
void operator() (void* sender, TEventArgs& e)
{
m_signal(sender, e);
}
private:
SignalType m_signal;
};
class IEventListener : public boost::signals::trackable
{
};
};
};
如您所见,我使用 boost::signal 作为我的实际事件系统,但我用 IEvent 接口(interface)(它实际上是一个抽象类)封装它以防止事件监听器通过 operator() 触发事件.
为了方便,我重载了加赋值和减赋值运算符。如果我现在确实从 IEventListener 派生我的事件监听类,我就能够编写代码而无需担心信号中的悬挂函数指针。
到目前为止,我正在测试我的结果,但我遇到了 std::tr1::function::target<TFuncPtr>() 的问题:
class BaseEventArgs : public Utils::Gui::EventArgs
{
};
class DerivedEventArgs : public BaseEventArgs
{
};
void Event_BaseEventRaised(void* sender, BaseEventArgs& e)
{
std::cout << "Event_BaseEventRaised called";
}
void Event_DerivedEventRaised(void* sender, DerivedEventArgs& e)
{
std::cout << "Event_DerivedEventRaised called";
}
int main()
{
using namespace Utils::Gui;
typedef EventHandler<BaseEventArgs>::HandlerPtr pfnBaseEventHandler;
typedef EventHandler<DerivedEventArgs>::HandlerPtr pfnNewEventHandler;
// BaseEventHandler with a function taking a BaseEventArgs
EventHandler<BaseEventArgs> baseEventHandler(Event_BaseEventRaised);
// DerivedEventHandler with a function taking a DerivedEventArgs
EventHandler<DerivedEventArgs> newEventHandler(Event_DerivedEventRaised);
// DerivedEventHandler with a function taking a BaseEventArgs -> Covariance
EventHandler<DerivedEventArgs> covariantBaseEventHandler(Event_BaseEventRaised);
const pfnBaseEventHandler* pBaseFunc = baseEventHandler.target<pfnBaseEventHandler>();
std::cout << "baseEventHandler function pointer is " << ((pBaseFunc != nullptr) ? "valid" : "invalid") << std::endl;
const pfnNewEventHandler* pNewFunc = newEventHandler.target<pfnNewEventHandler>();
std::cout << "baseEventHandler function pointer is " << ((pNewFunc != nullptr) ? "valid" : "invalid") << std::endl;
// Here is the error, covariantBaseEventHandler actually stores a pfnBaseEventHandler:
pNewFunc = covariantBaseEventHandler.target<pfnNewEventHandler>();
std::cout << "covariantBaseEventHandler as pfnNewEventHandler function pointer is " << ((pNewFunc != nullptr) ? "valid" : "invalid") << std::endl;
// This works as expected, but template forces compile-time knowledge of the function pointer type
pBaseFunc = covariantBaseEventHandler.target<pfnBaseEventHandler>();
std::cout << "covariantBaseEventHandler as pfnBaseEventHandler function pointer is " << ((pBaseFunc != nullptr) ? "valid" : "invalid") << std::endl;
return EXIT_SUCCESS;
}
EventHandler<TEventArgs>::target<TFuncPtr>()如果 TFuncPtr 与 Functor 中存储的类型完全相同,则方法将仅返回一个有效指针,而不管协方差如何。
由于 RTTI 检查,它禁止将指针作为标准弱类型 C 函数指针访问,这在这种情况下有点烦人。
EventHandler 是 DerivedEventArgs 类型,但仍然指向 pfnBaseEventHandler 函数,即使该函数通过构造函数运行。
这意味着,std::tr1::function 本身“支持”逆变,但如果我不这样做的话,我无法找到一种简单地从 std::tr1::funcion 对象中获取函数指针的方法在编译时知道它的类型,这是模板参数所必需的。
在这种情况下,我很感激他们添加了一个简单的 get() 方法,就像他们为 RAII 指针类型所做的那样。
由于我是编程新手,我想知道是否有办法解决这个问题,最好是在编译时通过模板(我认为这是唯一的方法)。
最佳答案
刚刚找到了问题的解决方案。看来我只是错过了在不同位置的类型转换:
template<class TEventArgs>
class EventHandler : public std::function<void (void*, TEventArgs&)>
{
public:
typedef void Signature(void*, TEventArgs&);
typedef void (*HandlerPtr)(void*, TEventArgs&);
// ...
template<class TContravariantEventArgs>
EventHandler(const EventHandler<TContravariantEventArgs>& rhs)
: std::function<Signature>(reinterpret_cast<HandlerPtr>(*rhs.target<EventHandler<TContravariantEventArgs>::HandlerPtr>()))
{
static_assert(std::is_base_of<TContravariantEventArgs, TEventArgs>::value,
"The eventHandler instance to copy does not suffice the rules of contravariance.");
}
// ...
}
这是按预期方式工作的。尽管如此,还是感谢您顺利地向我介绍了这个非常棒的社区!
关于c++ - std::tr1::function::target<TFuncPtr> 和协变/逆变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3227926/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我在一个我想在formtasticGem中覆盖的方法中找到了这个。该方法如下所示:defto_htmlinput_wrappingdohidden_field_html是什么意思?在第三行做什么?我知道它对数组有什么作用,但在这里我不知道。 最佳答案 你可以这样读:hidden_field_htmllabel_with_nested_checkbox是连接到hidden_field_html末尾的参数-为了“清晰”,他们将其分成两行 关于ruby-on-rails-没有参数的`
我已经看到了一些其他的问题,尝试了他们的建议,但没有一个对我有用。我已经使用Rails大约一年了,刚刚开始一个新的Rails项目,突然遇到了问题。我卸载并尝试重新安装所有Ruby和Rails。Ruby很好,但Rails不行。当我输入railss时,我得到了can'tfindgemrailties。我当前的Ruby版本是ruby2.2.2p95(2015-04-13修订版50295)[x86_64-darwin15],尽管我一直在尝试通过rbenv设置ruby2.3.0。如果我尝试rails-v查看我正在运行的版本,我会得到同样的错误。我使用的是MacOSXElCapitan版本10
考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://