Jan Engelhardt
2014-02-26 21:40:57 UTC
In wxWidgets 3.0.0's include/wx/event.h, one can find:
wxEventFunctorFunctor(const Functor& handler)
: m_handler(handler), m_handlerAddr(&handler)
{ }
virtual bool IsMatching(const wxEventFunctor &functor) const
{
if ( wxTypeId(functor) != wxTypeId(*this) )
return false;
typedef wxEventFunctorFunctor<EventTag, Functor> FunctorThis;
const FunctorThis& other = static_cast<const FunctorThis&>(functor);
// The only reliable/portable way to compare two functors is by
// identity:
return m_handlerAddr == other.m_handlerAddr;
}
However, I believe the comparison is not reliable enough. Consider
this sample code which has two different handlers, but whose object
address happens to be the same:
---8<---
#include <wx/wx.h>
#include <cstdio>
class Main : public wxFrame {
public:
Main(void);
private:
void sub1(void);
void sub2(void);
wxButton *button1, *button2;
};
void Main::sub1(void)
{
auto func1 = [this](wxCommandEvent &) {
wxMessageDialog(this, "Hello world!").ShowModal();
};
printf("%p\n", &func1);
button1 = new wxButton(this, wxID_ANY, "Welcome it");
Bind(wxEVT_BUTTON, func1, button1->GetId());
}
void Main::sub2(void)
{
auto func2 = [this](wxCommandEvent &) {
wxMessageDialog(this, "Goodbye cruel world!").ShowModal();
};
printf("%p\n", &func2);
button2 = new wxButton(this, wxID_ANY, "Do away with it");
Bind(wxEVT_BUTTON, func2, button2->GetId());
}
Main::Main(void) : wxFrame(NULL, wxID_ANY, wxEmptyString) {
sub1();
sub2();
auto sz = new wxBoxSizer(wxHORIZONTAL);
sz->Add(button1, 1);
sz->Add(button2, 1);
SetSizer(sz);
sz->SetSizeHints(this);
}
class MyApp : public wxApp {
private: bool OnInit(void) {
(new Main)->Show();
return true;
};
};
IMPLEMENT_APP(MyApp);
--->8---
Breakpoint 1, Main::__lambda0::operator() (__closure=0x756708) at q.cpp:14
14 wxMessageDialog(this, "Hello world!").ShowModal();
(gdb) up
#1 0x000000000040c3d7 in wxEventFunctorFunctor<wxEventTypeTag<wxCommandEvent>, Main::sub1()::__lambda0>::operator()(wxEvtHandler *, wxEvent &) (
this=0x756700, event=...) at /usr/include/wx-3.0/wx/event.h:516
516 m_handler(static_cast<EventArg&>(event));
(gdb) p m_handlerAddr
warning: RTTI symbol not found for class 'wxEventFunctorFunctor<wxEventTypeTag<wxCommandEvent>, Main::sub1()::{lambda(wxCommandEvent&)#1}>'
$1 = (const void *) 0x7fffffffdc80
The special thing about lambdas is that they are not function pointers
(those would be unique), but are, in g++, class-like objects with an
operator() function. Given that, the problem with using the == test
inside IsMatching would also apply to non-lambda functors.
What you would probably want is to use the address of the anonymous
(unique) function inside the lambda which g++ internally calls
000000000040b98e t Main::sub1()::{lambda(wxCommandEvent&)#1}::operator()(wxCommandEvent&) const
That, however, is not exposed in the C++ language.
wxEventFunctorFunctor(const Functor& handler)
: m_handler(handler), m_handlerAddr(&handler)
{ }
virtual bool IsMatching(const wxEventFunctor &functor) const
{
if ( wxTypeId(functor) != wxTypeId(*this) )
return false;
typedef wxEventFunctorFunctor<EventTag, Functor> FunctorThis;
const FunctorThis& other = static_cast<const FunctorThis&>(functor);
// The only reliable/portable way to compare two functors is by
// identity:
return m_handlerAddr == other.m_handlerAddr;
}
However, I believe the comparison is not reliable enough. Consider
this sample code which has two different handlers, but whose object
address happens to be the same:
---8<---
#include <wx/wx.h>
#include <cstdio>
class Main : public wxFrame {
public:
Main(void);
private:
void sub1(void);
void sub2(void);
wxButton *button1, *button2;
};
void Main::sub1(void)
{
auto func1 = [this](wxCommandEvent &) {
wxMessageDialog(this, "Hello world!").ShowModal();
};
printf("%p\n", &func1);
button1 = new wxButton(this, wxID_ANY, "Welcome it");
Bind(wxEVT_BUTTON, func1, button1->GetId());
}
void Main::sub2(void)
{
auto func2 = [this](wxCommandEvent &) {
wxMessageDialog(this, "Goodbye cruel world!").ShowModal();
};
printf("%p\n", &func2);
button2 = new wxButton(this, wxID_ANY, "Do away with it");
Bind(wxEVT_BUTTON, func2, button2->GetId());
}
Main::Main(void) : wxFrame(NULL, wxID_ANY, wxEmptyString) {
sub1();
sub2();
auto sz = new wxBoxSizer(wxHORIZONTAL);
sz->Add(button1, 1);
sz->Add(button2, 1);
SetSizer(sz);
sz->SetSizeHints(this);
}
class MyApp : public wxApp {
private: bool OnInit(void) {
(new Main)->Show();
return true;
};
};
IMPLEMENT_APP(MyApp);
--->8---
Breakpoint 1, Main::__lambda0::operator() (__closure=0x756708) at q.cpp:14
14 wxMessageDialog(this, "Hello world!").ShowModal();
(gdb) up
#1 0x000000000040c3d7 in wxEventFunctorFunctor<wxEventTypeTag<wxCommandEvent>, Main::sub1()::__lambda0>::operator()(wxEvtHandler *, wxEvent &) (
this=0x756700, event=...) at /usr/include/wx-3.0/wx/event.h:516
516 m_handler(static_cast<EventArg&>(event));
(gdb) p m_handlerAddr
warning: RTTI symbol not found for class 'wxEventFunctorFunctor<wxEventTypeTag<wxCommandEvent>, Main::sub1()::{lambda(wxCommandEvent&)#1}>'
$1 = (const void *) 0x7fffffffdc80
The special thing about lambdas is that they are not function pointers
(those would be unique), but are, in g++, class-like objects with an
operator() function. Given that, the problem with using the == test
inside IsMatching would also apply to non-lambda functors.
What you would probably want is to use the address of the anonymous
(unique) function inside the lambda which g++ internally calls
000000000040b98e t Main::sub1()::{lambda(wxCommandEvent&)#1}::operator()(wxCommandEvent&) const
That, however, is not exposed in the C++ language.
--
Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.
To unsubscribe, send email to wx-users+***@googlegroups.com
or visit http://groups.google.com/group/wx-users
Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.
To unsubscribe, send email to wx-users+***@googlegroups.com
or visit http://groups.google.com/group/wx-users