c++11 : Compare lambda expression - c++

Imagine have the following class :
#include <functional>
#include <vector>
template<typename T1> class Signaler
{
public:
typedef std::function<void (T1)> Func;
public:
Signaler()
{
}
void Call(T1 arg)
{
for(Int32 i = (Int32)_handlers.size() - 1; i > -1; i--)
{
Func handler = _handlers[i];
handler(arg);
}
}
Signaler& operator+=(Func f)
{
_handlers.push_back( f );
return *this;
}
Signaler& operator-=(Func f)
{
for(auto i = _handlers.begin(); i != _handlers.end(); i++)
{
if ( (*i).template target<void (T1)>() == f.template target<void (T1)>() )
{
_handlers.erase( i );
break;
}
}
return *this;
}
private:
std::vector<Func> _handlers;
};
And I use it the following way :
Signaler Global::Signal_SelectionChanged;
class C1
{
public:
void Register()
{
Global::Signal_SelectionChanged += [&](SelectionChangedEventArgs* e) { this->selectionChangedEvent_cb(e); };
}
void Unregister()
{
Global::Signal_SelectionChanged -= [&](SelectionChangedEventArgs* e) { this->selectionChangedEvent_cb(e); };
}
void selectionChangedEvent_cb(SelectionChangedEventArgs* e) {}
};
class C2
{
public:
void Register()
{
Global::Signal_SelectionChanged += [&](SelectionChangedEventArgs* e) { this->selectionChangedEvent_cb(e); };
}
void Unregister()
{
Global::Signal_SelectionChanged -= [&](SelectionChangedEventArgs* e) { this->selectionChangedEvent_cb(e); };
}
void selectionChangedEvent_cb(SelectionChangedEventArgs* e) {}
};
Now, the problem that I have is when I call 'Unregister' from the class C2, it removes the wrong version of the 'lambda" expression, because the 'lambda' looks similar.
How can I solve this problem ?
Any idea ?
Thanks

The problem is that you are using std::function::target with a type that is not the type of the object stored in the std::function, so it is returning a null pointer. That is, you need to know the actual type of the object stored in the std::function to be able to call target.
Even if you were to call target with the lambda closure type used to add the callback, this wouldn't work for two reasons: first, lambda closure types are unique (5.1.2p3) so the += and -= lambdas have different types even if they are syntactically identical; second, the closure type for a lambda-expression is not defined to have an operator== (5.1.2p3-6, 19-20), so your code would not even compile.
Switching from lambdas to std::bind wouldn't help, as bind types are also not defined to have operator==.
Instead, consider using an id to register/unregister callbacks. You could also use your own functor which defines operator==, but that would be a lot of work.

Related

Universal Callback template class with pointer to method callback

Inspired by another article here on SO (C++ callback using class member) I tried to write a universal CallbackHandler.
CallbackHandler.hpp
#pragma once
#include <functional>
template <typename CallbackClass, typename CallbackArgType>
class CallbackHandler
{
public:
std::function<void(CallbackArgType ct)> m_callbackFunc;
CallbackHandler(CallbackClass * handler, std::function<void(CallbackArgType)> method)
{
//m_callbackFunc is supposed to stand for a member to pointer callback function with one
//parameter of any type
m_callbackFunc = std::bind(method, handler, std::placeholders::_1);
}
};
#include "wrapper_T.cpp"
I want to use it in several other templated namespaces/classes like here:
wrapper.hpp
//this wrappers main purpose is to combine the constructor of a non templated class (MyModule)
//and hold a (global) callback method for it (m_parentCallback)
namespace wrapper
{
extern std::function<void(wxImage *)> m_parentCallback;
template<typename ParentClass>
MyModule GetNewModule(ParentClass* parent, void (ParentClass::* method)(wxImage *));
}
wrapper.cpp
namespace wrapper
{
//This is only to avoid multiple definition error - actual definition is in wrapper_T.cpp
std::function<void(wxImage *)> m_parentCallback;
}
wrapper_T.cpp
namespace wrapper
{
template<typename ParentClass>
MyModule GetNewModule(ParentClass* parent, void (ParentClass::* method)(wxImage *))
{
//the callback type of this wrapper/class is wxImage*
std::shared_ptr<CallbackHandler<ParentClass, wxImage*>> handler =
std::make_shared< CallbackHandler<ParentClass, wxImage*>>(parent, method);
//EDIT - SOLVED: <- Error C2664: Cant convert argument 2 from "void (__thiscall MyModule::*)(void)" to "std::function<void(wxImage*)>"
m_parentCallback = std::bind(&CallbackHandler<ParentClass, wxImage*>::m_callbackFunc, handler, std::placeholders::_1);
//<- Error C2679: no suitable binary operator "=" found
return std::make_unique<MyModule>();
}
}
I wanted to use the callback like this:
MyModule.cpp
wrapper::m_parentCallback(&img);
I want to initialize the whole thing like this:
MainClass.cpp
MainClass::MainClass()
{
//declared in header: std::unique_ptr<MyModule> module
module = std::move(wrapper::GetNewModule(this, &MainClass::CallbackFunc));
}
void MainClass::CallbackFunc(wxImage * img)
{ /* do something with it */ }
I have the class with the "this" pointer and the pointer to method "CallbackFunc", which should be alright.
But I dont see how to use my CallbackHandler class for a std::function callback pointer.
Or did I overdo it with the wrapper holding a pointer to a method of the CallbackHandler, which holds a pointer to a method of the actual callback method?
All of this is no design choice, I just want the CallbackHandler to be portable and working, while having an interface which is easy to use.
EDIT:
I tried to apply the comments suggestions on the code, but I was to fast
with claiming the first problem was solved. The error was just hidden by the next error. If I try to compile with just this line:
std::shared_ptr<CallbackHandler<ParentClass, wxImage*>> handler =
std::make_shared< CallbackHandler<ParentClass, wxImage*>>(parent, method);
//<- Error C2664: "CallbackHandler<ParentClass,wxImage *>::
//CallbackHandler(CallbackHandler<ParentClass,wxImage *> &&)"
//: converting argument 2 from "void (__thiscall MainClass::* )(wxImage *)"
//to "std::function<void (wxImage *)>" not possible
// with
// [
// ParentClass=MainClass
]
//(freely translated into english by me)
So, the missing argument was not the only problem.
If std::bind on methods (member functions) does not work, I do have to change the CallbackClass as well, dont I?
Maybe something along those lines:
std::function<void(CallbackArgType cat)> m_callbackFunc;
CallbackHandler(CallbackClass * handler, std::function<void(CallbackArgType)> method)
{
//m_callbackFunc = std::bind(method, handler, std::placeholders::_1);
m_callbackFunc = [method](auto img) { method(img); };
}
Replace
m_parentCallback = std::bind(&CallbackHandler<ParentClass, wxImage*>::m_callbackFunc, handler, std::placeholders::_1);
with
m_parentCallback = [handler](auto img){ handler->m_parentCallback(img); };
I don't think bind was designed to work with member functor objects on top of everything. But lambdas handle that seamlessly.
I noticed that my problem is beeing solved by every event handler, calling an event function. So I used an event handler as basis vor my CallbackHandler. I found and used this event handler, as there are most certainly many other good written examples:
https://www.codeproject.com/Articles/1256352/CppEvent-How-to-Implement-Events-using-Standard-Cp#holdingHandlerFunction
I just wrapped it in a class and it is a little overkill for my purpose, but it works. All credits to Shmuel Zang (see link above)
EventHandler.hpp
#ifndef EventHandler_hpp
#define EventHandler_hpp
// https://www.codeproject.com/Articles/1256352/CppEvent-How-to-Implement-Events-using-Standard-Cp#holdingHandlerFunction
#include <functional>
#include <list>
#include <algorithm>
#include <utility>
#include <atomic>
#include <mutex>
#include <future>
namespace EventHandler
{
template <typename... Args> class EventHandler_Base
{
public:
typedef std::function<void(Args...)> handler_func_type;
typedef unsigned int handler_id_type;
explicit EventHandler_Base(const handler_func_type& handlerFunc)
: m_handlerFunc(handlerFunc)
{
m_handlerId = ++m_handlerIdCounter;
}
// copy constructor
EventHandler_Base(const EventHandler_Base& src)
: m_handlerFunc(src.m_handlerFunc), m_handlerId(src.m_handlerId)
{
}
// move constructor
EventHandler_Base(EventHandler_Base&& src)
: m_handlerFunc(std::move(src.m_handlerFunc)), m_handlerId(src.m_handlerId)
{
}
// copy assignment operator
EventHandler_Base& operator=(const EventHandler_Base& src)
{
m_handlerFunc = src.m_handlerFunc;
m_handlerId = src.m_handlerId;
return *this;
}
// move assignment operator
EventHandler_Base& operator=(EventHandler_Base&& src)
{
std::swap(m_handlerFunc, src.m_handlerFunc);
m_handlerId = src.m_handlerId;
return *this;
}
// function call operator
void operator()(Args... params) const
{
if (m_handlerFunc)
{
m_handlerFunc(params...);
}
}
bool operator==(const EventHandler_Base& other) const
{
return m_handlerId == other.m_handlerId;
}
operator bool() const
{
return m_handlerFunc;
}
handler_id_type id() const
{
return m_handlerId;
}
private:
handler_func_type m_handlerFunc;
handler_id_type m_handlerId;
static std::atomic_uint m_handlerIdCounter;
};
template <typename... Args> std::atomic_uint EventHandler_Base<Args...>::m_handlerIdCounter(0);
template <typename... Args> class Event_Base
{
public:
typedef EventHandler_Base<Args...> handler_type;
Event_Base()
{
}
// copy constructor
Event_Base(const Event_Base& src)
{
std::lock_guard<std::mutex> lock(src.m_handlersLocker);
m_handlers = src.m_handlers;
}
// move constructor
Event_Base(Event_Base&& src)
{
std::lock_guard<std::mutex> lock(src.m_handlersLocker);
m_handlers = std::move(src.m_handlers);
}
// copy assignment operator
Event_Base& operator=(const Event_Base& src)
{
std::lock_guard<std::mutex> lock(m_handlersLocker);
std::lock_guard<std::mutex> lock2(src.m_handlersLocker);
m_handlers = src.m_handlers;
return *this;
}
// move assignment operator
Event_Base& operator=(Event_Base&& src)
{
std::lock_guard<std::mutex> lock(m_handlersLocker);
std::lock_guard<std::mutex> lock2(src.m_handlersLocker);
std::swap(m_handlers, src.m_handlers);
return *this;
}
typename handler_type::handler_id_type add(const handler_type& handler)
{
std::lock_guard<std::mutex> lock(m_handlersLocker);
m_handlers.push_back(handler);
return handler.id();
}
inline typename handler_type::handler_id_type add(const typename handler_type::handler_func_type& handler)
{
return add(handler_type(handler));
}
bool remove(const handler_type& handler)
{
std::lock_guard<std::mutex> lock(m_handlersLocker);
auto it = std::find(m_handlers.begin(), m_handlers.end(), handler);
if (it != m_handlers.end())
{
m_handlers.erase(it);
return true;
}
return false;
}
bool remove_id(const typename handler_type::handler_id_type& handlerId)
{
std::lock_guard<std::mutex> lock(m_handlersLocker);
auto it = std::find_if(m_handlers.begin(), m_handlers.end(),
[handlerId](const handler_type& handler) { return handler.id() == handlerId; });
if (it != m_handlers.end())
{
m_handlers.erase(it);
return true;
}
return false;
}
void call(Args... params) const
{
handler_collection_type handlersCopy = get_handlers_copy();
call_impl(handlersCopy, params...);
}
std::future<void> call_async(Args... params) const
{
return std::async(std::launch::async, [this](Args... asyncParams) { call(asyncParams...); }, params...);
}
inline void operator()(Args... params) const
{
call(params...);
}
inline typename handler_type::handler_id_type operator+=(const handler_type& handler)
{
return add(handler);
}
inline typename handler_type::handler_id_type operator+=(const typename handler_type::handler_func_type& handler)
{
return add(handler);
}
inline bool operator-=(const handler_type& handler)
{
return remove(handler);
}
protected:
typedef std::list<handler_type> handler_collection_type;
void call_impl(const handler_collection_type& handlers, Args... params) const
{
for (const auto& handler : handlers)
{
handler(params...);
}
}
handler_collection_type get_handlers_copy() const
{
std::lock_guard<std::mutex> lock(m_handlersLocker);
// Since the function return value is by copy,
// before the function returns (and destruct the lock_guard object),
// it creates a copy of the m_handlers container.
return m_handlers;
}
private:
handler_collection_type m_handlers;
mutable std::mutex m_handlersLocker;
};
}
#endif // EventHandler_hpp
I then use this generic class to save a callback member method:
CallbackHandler.hpp
#ifndef CallbackHandler_hpp
#define CallbackHandler_hpp
#pragma once
#include "EventHandler.hpp"
#include <functional>
#include <mutex>
using namespace EventHandler;
template <typename... Args>
class CallbackHandler
{
public:
typedef std::function<void(Args...)> callbackFunc_type;
explicit CallbackHandler() : mb_callbackIsSet(false), mi_handlerID(0){}
explicit CallbackHandler(const callbackFunc_type& handlerFunc) : mb_callbackIsSet(false), mi_handlerID(0)
{
SetCallbackMethod(handlerFunc);
}
~CallbackHandler()
{
m_callbackEvent.remove_id(mi_handlerID);
}
void SetCallbackMethod(const callbackFunc_type& handlerFunc)
{
m_callbackEvent.remove_id(mi_handlerID);
mi_handlerID = m_callbackEvent.add([=](Args... params) {
handlerFunc(params...);
});
mb_callbackIsSet = true;
}
bool DoCallback(Args... params)
{
if (mb_callbackIsSet)
{
std::lock_guard<std::mutex> lock(callbackLocker);
m_callbackEvent(params...);
return true;
}
return false;
}
private:
unsigned int mi_handlerID;
Event_Base<Args...> m_callbackEvent;
bool mb_callbackIsSet;
std::mutex callbackLocker;
};
#endif //CallbackHandler_hpp
I can use the CallbackHandler in every other class now:
//Imagine an example class named Screenshotmodul
//In this example I use wxImage as a callback object, it is the output of my Screenshotmodul class and should be given back to my main class
//It could be any other (or several others like this: <ObjectType, OtherCallbackType> )
class Screenshotmodul
{
public:
//[...]
CallbackHandler<wxImage> m_callbackHandler;
template<typename ParentClass>
void SetCallbackMethod(ParentClass* parent, void (ParentClass::* method)(wxImage))
{
//using the given object pointer and the given member method in a lambda function
//saving that lambda as callback method
m_callbackHandler.SetCallbackMethod([=](wxImage img) {
(parent->*method)(img); });
}
}
In my main class I can then set a callback method:
std::unique_ptr<Screenshotmodul> sm = std::make_unique<Screenshotmodul>();
sm->SetCallbackMethod(this, &MyMainClass::CallbackfuncForScreenshotmodul);
//Of course there should be a callback function as just described:
void MyMainClass::CallbackfuncForScreenshotmodul(wxImage img)
{
//img now contains the callback value, that the Screenshotmodul class created
}
This is my approach and it is not perfect, but it works for me.
Cheers
Natu

creating type vector in c++

I have several classes that each of them has an ID and the Id is passed to the class as a template parameter:
typedef class1<1> baseClass;
typedef class2<2> baseClass;
typedef class<100> baseClass;
Now I need a map so if I can associate 1 with Class1 and 2 with Class2 and so on.
How can I create such vector? I am working on a header only library, so it should be a header only definition.
I am looking something that do the same thing that this code would do (if someone can compile it!):
std::map<int,Type> getMap()
{
std::map<int,Type> output;
output.add(1,class1);
output.add(2,class2);
output.add(100,class100);
}
The idea is that when I get as input 1, I create a class1 and when I receive 2, I create class2.
Any suggestion is very appreciated.
using this data, then I can write a function like this:
void consume(class1 c)
{
// do something interesting with c
}
void consume(class2 c)
{
// do something interesting with c
}
void consume(class3 c)
{
// do something interesting with c
}
void consume(int id,void * buffer)
{
auto map=getMap();
auto data= new map[id](buffer); // assuming that this line create a class based on map, so the map provide the type that it should be created and then this line create that class and pass buffer to it.
consume(data);
}
As a sketch:
class BaseClass { virtual ~BaseClass() = default; };
template<std::size_t I>
class SubClass : public BaseClass {};
namespace detail {
template<std::size_t I>
std::unique_ptr<BaseClass> makeSubClass() { return { new SubClass<I> }; }
template<std::size_t... Is>
std::vector<std::unique_ptr<BaseClass>(*)> makeFactory(std::index_sequence<Is...>)
{ return { makeSubclass<Is>... }; }
}
std::vector<std::unique_ptr<BaseClass>(*)> factory = detail::makeFactory(std::make_index_sequence<100>{});
We populate the vector by expanding a parameter pack, so we don't have to write out all 100 instantiations by hand. This gives you Subclass<0> at factory[0], Subclass<1> at factory[1], etc. up to Subclass<99> at factory[99].
If I understand correctly you want a map to create different types according to a given number.
If that is so, then the code should look something like this:
class Base
{
};
template <int number>
class Type : public Base
{
public:
Type()
{
std::cout << "type is " << number << std::endl;
}
};
using Type1 = Type<1>;
using Type2 = Type<2>;
using Type3 = Type<3>;
using CreateFunction = std::function<Base*()>;
std::map<int, CreateFunction> creators;
int main()
{
creators[1] = []() -> Base* { return new Type1(); };
creators[2] = []() -> Base* { return new Type2(); };
creators[3] = []() -> Base* { return new Type3(); };
std::vector<Base*> vector;
vector.push_back(creators[1]());
vector.push_back(creators[2]());
vector.push_back(creators[3]());
}
output:
type is 1
type is 2
type is 3
If you need only to create object, it would be enough to implement template creator function like:
template<int ID>
Base<ID> Create()
{
return Base<ID>();
}
And then use it:
auto obj1 = Create<1>();
auto obj2 = Create<2>();
// etc
Working example: https://ideone.com/urh7h6
Due to C++ being a statically-typed language, you may choose to either have arbitrary types that do a fixed set of things or have a fixed set of types do arbitrary things, but not both.
Such limitations is embodied by std::function and std::variant. std::function can have arbitrary types call operator() with a fixed signature, and std::variant can have arbitrary functions visit the fixed set of types.
Since you already said the types may be arbitrary, you may only have a fixed set of things you can do with such a type (e.g. consume). The simplest way is to delegate the hard work to std::function
struct Type
{
template<typename T>
Type(T&& t)
: f{[t = std::forward<T>(t)]() mutable { consume(t); }} {}
std::function<void()> f;
};
void consume(Type& t)
{
t.f();
}
What you are looking for is either the Stategy pattern:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class A {
public:
A() {}
virtual void doIt() {};
};
class Aa : public A {
public:
Aa() {}
virtual void doIt() {
std::cout << "do it the Aa way" << std::endl;
}
};
class Ab : public A {
public:
Ab() {}
virtual void doIt() {
std::cout << "do it the Ab way" << std::endl;
}
};
class Concrete {
public:
Concrete(std::string const& type) {
if (type == ("Aa")) {
_a.reset(new Aa());
} else if (type == "Ab") {
_a.reset(new Ab());
}
}
void doIt () const {
_a->doIt();
}
private:
std::unique_ptr<A> _a;
};
int main() {
std::vector<Concrete> vc;
vc.push_back(Concrete("Aa"));
vc.push_back(Concrete("Ab"));
for (auto const& i : vc) {
i.doIt();
}
return 0;
}
Will output:
do it the Aa way
do it the Ab way

Call a function before function exits

I will begin with an example. Suppose I need to guard a code with a function inside a mutex. There are two ways of implementing this.
#include <iostream>
#include <vector>
#include <pthread.h>
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
std::vector<float> myVec;
void threadfunc(int i, float value)
{
pthread_mutex_lock(&myMutex);
if(i <= 0 || i > myVec.size())
{
pthread_mutex_unlock(&myMutex);
return;
}
if(value < 0)
{
pthread_mutex_unlock(&myMutex);
return;
}
myVec[i] += value;
pthread_mutex_unlock(&myMutex);
return;
}
class AUTOMUTEX
{
private:
pthread_mutex_t *mMutex;
public:
AUTOMUTEX(pthread_mutex_t *mutex): mMutex(mutex)
{
pthread_mutex_lock(mMutex);
}
~AUTOMUTEX()
{
pthread_mutex_unlock(mMutex);
}
};
void threadfunc_autolock(int i, float value)
{
AUTOMUTEX autoMutex(&myMutex);
if(i <= 0 || i > myVec.size())
{
return;
}
if(value < 0)
{
return;
}
myVec[i] += value;
return;
}
int main()
{
threadfunc_autolock(5, 10);
threadfunc(0, 7);
return 1;
}
As it is clear from the example threadfunc autolock is better implementation as calling pthread_mutex_unlock function return is taken care by destructor call to AUTOMUTEX (C++ 11 thread has support for this. So we don't need our own implementation of AUTOMUTEX if we are using C++11 thread library).
Is there a way we can achieve this without implementing a wrapper class each time we need to do this with some set/reset function pair. Does boost or C++ 11 have some predefined template class with which we can achieve the behaviour of AUTOMUTEX for any such "set/reset" sort of function. This is really helpful for functions with multiple points of return.
In other words does boost/C++ provide a class with the following behaviour.
//sample code not compilable.
template <class T, class Y>
class myAuto
{
myAuto()
{
T();
}
~myAuto()
{
Y();
};
You may write your own geneirc RAII class, something like:
class Finally
{
public:
explicit Finally(std::function<void()> f) : mF(f) {}
~Finally() noexcept() {
try
{
mF();
} catch (...) {
// Handle error.
}
}
Finally(const Finally&) = delete;
Finally(Finally&&) = delete;
Finally& operator=(const Finally&) = delete;
Finally& operator=(Finally&&) = delete;
private:
std::function<void()> mF;
};
Usage:
{
pthread_mutex_lock(&myMutex);
Finally finally([&](){ pthread_mutex_unlock(&myMutex); });
//..
}
Even if a dedicated RAII object may be more appropriate in some case (as Mutex).
There is a proposal for a generic scope guard to be included in the next C++ standard, and I think it is accepted. You can find an implementation here, together with a link to the reference paper.
In principle, it is similar to the classical ScopeGuard, but it also provides some special cases e.g. for C-like file APIs.
You could use something like ScopeGuard. (Now somewhat old-fashioned.)
But given how easy and clear it is to construct a specific RAII wrapper for each resource type I would normally do that.
(I don't think boost ever adopted anything like ScopeGuard. With std::function, lambdas and so on it's easy to do your own.)
What's wrong with writing your own generic resource wrapper?
template <typename Res, typename Fn = std::function<void(Res*)>>
class resource_mgr
{
Res* resource;
Fn initialize, finalize;
public:
resource_mgr (Res* r, Fn i, Fn f)
: resource(r),
initialize(i),
finalize(f)
{
initialize(resource);
}
resource_mgr (resource_mgr const&) = delete;
resource_mgr (resource_mgr&&) = delete;
resource_mgr const& operator = (resource_mgr const&) = delete;
resource_mgr const& operator = (resource_mgr&&) = delete;
~resource_mgr
{
try
{
finalize(resource);
}
catch(...)
{
std::cerr << "Uh-oh!"
}
}
};
You can keep it simple or go wild on something like this -- use smart pointers, define move operations, add support for custom error handlers, etc. You might use it like this:
void threadfunc_autolock(int i, float value)
{
resource_mgr<mutex_t> autoMutex (
&myMutex,
[](auto* p) { if (!pthread_mutex_lock(p)) throw Something(); },
[](auto* p) { if (!pthread_mutex_unlock(p)) throw Something(); }
);
/* . . . */
}
Here's an example using Boost.ScopeExit (untested):
#include <boost/scope_exit.hpp>
...
void threadfunc_autolock(int i, float value)
{
pthread_mutex_lock(&myMutex);
BOOST_SCOPE_EXIT(&myMutex) {
pthread_mutex_unlock(&myMutex);
} BOOST_SCOPE_EXIT_END
if(i <= 0 || i > myVec.size())
{
return;
}
if(value < 0)
{
return;
}
myVec[i] += value;
}

Using Lambda/Template/SFINAE to automate try/catch-safeguarding of trampoline functions

I have 100 or so trampoline functions. I would like to know whether it is possible to automate wrapping each one inside a try/catch block.
Please be warned in advance, this is not an easy question. I will start by describing the problem with (simplified) code, and will then attempt to answer it as best I can below, so the reader may see where I am at.
Foo has a function pointer table:
EDIT: This is a C function pointer table. So it could accept static W::w.
Signatures are here: http://svn.python.org/projects/python/trunk/Include/object.h
EDIT: I've attempted a test case here:
class Foo {
Table table;
Foo() {
// Each slot has a default lambda.
:
table->fp_53 = [](S s, A a, B b) -> int {cout<<"load me!";};
table->fp_54 = [](S s, C c, D d, E e) -> float {cout<<"load me!";};
// ^ Note: slots MAY have different signatures
// only the first parameter 'S s' is guaranteed
}
// Foo also has a method for loading a particular slot:
:
void load53() { table->fp_53 = func53; }
void load54() { table->fp_54 = func54; }
:
}
If a particular slot is 'loaded', this is what gets loaded into it:
int func53(S s, A a, B b) {
try{
return get_base(s)->f53(a,b);
}
catch(...) { return 42;}
}
float func54(S s, C c, D d, E e) {
try{
return get_base(s)->f54(c,d,e);
}
catch(...) { return 3.14;}
}
I am trying to accomplish this using lambdas, so as to bypass having to define all of these func53 separately. Something like this:
class Foo {
:
void load53() {
table->fp_53 =
[](S s, A a, B b)->int { return get_base(s)->f53(a,b); }
}
void load54() {
table->fp_54 =
[](S s, C c, D d, E e)->float { return get_base(s)->f54(c,d,e); }
}
However, this is failing to trap errors. I need to be putting a try/catch around the return statement:
try{ return get_base(s)->f53(a,b); } catch{ return 42; }
However, this creates a lot of clutter. It would be nice if I could do:
return trap( get_base(s)->f53(a,b); )
My question is: is there any way to write this trap function (without using #define)?
This is what I've come up with so far:
I think this would pass all the necessary information:
trap<int, &Base::f53>(s,a,b)
trap's definition could then look like this:
template<typename RET, Base::Func>
static RET
trap(S s, ...) {
try {
return get_base(s)->Func(...);
}
catch {
return std::is_integral<RET>::value ? (RET)(42) : (RET)(3.14);
}
}
This may allow for a very clean syntax:
class Foo {
:
void load53() { table->fp_53 = &trap<int, &Base::f53>; }
void load54() { table->fp_54 = &trap<float, &Base::f54>; }
}
At this point I'm not even sure whether some laws have been violated. table->fp_53 must be a valid C function pointer.
Passing in the address of a nonstatic member function (&Base::f53>) won't violate this, as it is a template parameter, and is not affecting the signature for trap
Similarly, ... should be okay as C allows varargs.
So if this is indeed valid, can it be cleaned up?
My thoughts are:
1) maybe the ... should be moved back to the template parameter as a pack.
2) maybe it is possible to deduce the return type for trap, and save one template parameter
3) that Base::Func template parameter is illegal syntax. And I suspect it isn't even close to something legal. Which might scupper the whole approach.
#include <utility>
template <typename T, T t>
struct trap;
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R call(int s, Args... args)
{
try
{
return (get_base(s)->*t)(std::forward<Args>(args)...);
}
catch (...)
{
return std::is_integral<R>::value ? static_cast<R>(42)
: static_cast<R>(3.14);
}
}
};
Usage:
table->fp_53 = &trap<decltype(&Base::f53), &Base::f53>::call;
table->fp_54 = &trap<decltype(&Base::f54), &Base::f54>::call;
DEMO
Note: std::forward can still be used although Args is not a forwarding reference itself.
template<typename RET, typename... Args>
struct trap_base {
template<RET (Base::* mfptr)(Args...)>
static RET
trap(S s, Args... args) {
try {
return (get_base(s).*mfptr)(args...);
}
catch (...) {
return std::is_integral<RET>::value ? (RET)(42) : (RET)(3.14);
}
}
};
Usage:
void load53() { table.fp_53 = &trap_base<int, int>::trap<&Base::f53>; }
void load54() { table.fp_54 = &trap_base<float, int, float>::trap<&Base::f54>; }
Demo.
You can probably also use a partial specialization to extract RET and Args from decltype(&base::f53) etc.
trap_gen is a function that returns a function pointer to a function generated on the fly, the equivalent of your trap function.
Here is how you use it
table->fp_53 = trap_gen<>(Base::f53);
table->fp_54 = trap_gen<>(Base::f54);
...
Where Base::f53 and Base::f54 are static member functions (or function pointers, or global functions in a namespace).
Proof of concept :
#include <iostream>
template<typename R, class...A>
R (*trap_gen(R(*f)(A...)))(A...)
{
static auto g = f;
return [](A... a)
{
try {
return g(a...);
} catch (...) {
return std::is_integral<R>::value ? static_cast<R>(42)
: static_cast<R>(3.14);
}
};
}
int add(int a, int b)
{
return a+b;
}
int main() {
int(*f)(int, int) = trap_gen<>(add);
std::cout << f(2, 3) << std::endl;
return 0;
}

C++11 observer pattern (signals, slots, events, change broadcaster/listener, or whatever you want to call it)

With the changes made in C++11 (such as the inclusion of std::bind), is there a recommended way to implement a simple single-threaded observer pattern without dependence on anything external to the core language or standard library (like boost::signal)?
EDIT
If someone could post some code showing how dependence on boost::signal could be reduced using new language features, that would still be very useful.
I think that bind makes it easier to create slots (cfr. the 'preferred' syntax vs. the 'portable' syntax - that's all going away). The observer management, however, is not becoming less complex.
But as #R. Martinho Fernandes mentions: an std::vector<std::function< r(a1) > > is now easily created without the hassle for an (artificial) 'pure virtual' interface class.
Upon request: an idea on connection management - probably full of bugs, but you'll get the idea:
// note that the Func parameter is something
// like std::function< void(int,int) > or whatever, greatly simplified
// by the C++11 standard
template<typename Func>
struct signal {
typedef int Key; //
Key nextKey;
std::map<Key,Func> connections;
// note that connection management is the same in C++03 or C++11
// (until a better idea arises)
template<typename FuncLike>
Key connect( FuncLike f ) {
Key k=nextKey++;
connections[k]=f;
return k;
}
void disconnect(Key k){
connections.erase(k);
}
// note: variadic template syntax to be reviewed
// (not the main focus of this post)
template<typename Args...>
typename Func::return_value call(Args... args){
// supposing no subcription changes within call:
for(auto &connection: connections){
(*connection.second)(std::forward(...args));
}
}
};
Usage:
signal<function<void(int,int)>> xychanged;
void dump(int x, int y) { cout << x << ", " << y << endl; }
struct XY { int x, y; } xy;
auto dumpkey=xychanged.connect(dump);
auto lambdakey=xychanged.connect([&xy](int x, int y){ xy.x=x; xy.y=y; });
xychanged.call(1,2);
Since you're asking for code, my blog entry Performance of a C++11 Signal System contains a single-file implementation of a fully functional signal system based on C++11 features without further dependencies (albeit single-threaded, which was a performance requirement).
Here is a brief usage example:
Signal<void (std::string, int)> sig2;
sig2() += [] (std::string msg, int d) { /* handler logic */ };
sig2.emit ("string arg", 17);
More examples can be found in this unit test.
I wrote my own light weight Signal/Slot classes which return connection handles. The existing answer's key system is pretty fragile in the face of exceptions. You have to be exceptionally careful about deleting things with an explicit call. I much prefer using RAII for open/close pairs.
One notable lack of support in my library is the ability to get a return value from your calls. I believe boost::signal has methods of calculating the aggregate return values. In practice usually you don't need this and I just find it cluttering, but I may come up with such a return method for fun as an exercise in the future.
One cool thing about my classes is the Slot and SlotRegister classes. SlotRegister provides a public interface which you can safely link to a private Slot. This protects against external objects calling your observer methods. It's simple, but nice encapsulation.
I do not believe my code is thread safe, however.
//"MIT License + do not delete this comment" - M2tM : http://michaelhamilton.com
#ifndef __MV_SIGNAL_H__
#define __MV_SIGNAL_H__
#include <memory>
#include <utility>
#include <functional>
#include <vector>
#include <set>
#include "Utility/scopeGuard.hpp"
namespace MV {
template <typename T>
class Signal {
public:
typedef std::function<T> FunctionType;
typedef std::shared_ptr<Signal<T>> SharedType;
static std::shared_ptr< Signal<T> > make(std::function<T> a_callback){
return std::shared_ptr< Signal<T> >(new Signal<T>(a_callback, ++uniqueId));
}
template <class ...Arg>
void notify(Arg... a_parameters){
if(!isBlocked){
callback(std::forward<Arg>(a_parameters)...);
}
}
template <class ...Arg>
void operator()(Arg... a_parameters){
if(!isBlocked){
callback(std::forward<Arg>(a_parameters)...);
}
}
void block(){
isBlocked = true;
}
void unblock(){
isBlocked = false;
}
bool blocked() const{
return isBlocked;
}
//For sorting and comparison (removal/avoiding duplicates)
bool operator<(const Signal<T>& a_rhs){
return id < a_rhs.id;
}
bool operator>(const Signal<T>& a_rhs){
return id > a_rhs.id;
}
bool operator==(const Signal<T>& a_rhs){
return id == a_rhs.id;
}
bool operator!=(const Signal<T>& a_rhs){
return id != a_rhs.id;
}
private:
Signal(std::function<T> a_callback, long long a_id):
id(a_id),
callback(a_callback),
isBlocked(false){
}
bool isBlocked;
std::function< T > callback;
long long id;
static long long uniqueId;
};
template <typename T>
long long Signal<T>::uniqueId = 0;
template <typename T>
class Slot {
public:
typedef std::function<T> FunctionType;
typedef Signal<T> SignalType;
typedef std::shared_ptr<Signal<T>> SharedSignalType;
//No protection against duplicates.
std::shared_ptr<Signal<T>> connect(std::function<T> a_callback){
if(observerLimit == std::numeric_limits<size_t>::max() || cullDeadObservers() < observerLimit){
auto signal = Signal<T>::make(a_callback);
observers.insert(signal);
return signal;
} else{
return nullptr;
}
}
//Duplicate Signals will not be added. If std::function ever becomes comparable this can all be much safer.
bool connect(std::shared_ptr<Signal<T>> a_value){
if(observerLimit == std::numeric_limits<size_t>::max() || cullDeadObservers() < observerLimit){
observers.insert(a_value);
return true;
}else{
return false;
}
}
void disconnect(std::shared_ptr<Signal<T>> a_value){
if(!inCall){
observers.erase(a_value);
} else{
disconnectQueue.push_back(a_value);
}
}
template <typename ...Arg>
void operator()(Arg... a_parameters){
inCall = true;
SCOPE_EXIT{
inCall = false;
for(auto& i : disconnectQueue){
observers.erase(i);
}
disconnectQueue.clear();
};
for (auto i = observers.begin(); i != observers.end();) {
if (i->expired()) {
observers.erase(i++);
} else {
auto next = i;
++next;
i->lock()->notify(std::forward<Arg>(a_parameters)...);
i = next;
}
}
}
void setObserverLimit(size_t a_newLimit){
observerLimit = a_newLimit;
}
void clearObserverLimit(){
observerLimit = std::numeric_limits<size_t>::max();
}
int getObserverLimit(){
return observerLimit;
}
size_t cullDeadObservers(){
for(auto i = observers.begin(); i != observers.end();) {
if(i->expired()) {
observers.erase(i++);
}
}
return observers.size();
}
private:
std::set< std::weak_ptr< Signal<T> >, std::owner_less<std::weak_ptr<Signal<T>>> > observers;
size_t observerLimit = std::numeric_limits<size_t>::max();
bool inCall = false;
std::vector< std::shared_ptr<Signal<T>> > disconnectQueue;
};
//Can be used as a public SlotRegister member for connecting slots to a private Slot member.
//In this way you won't have to write forwarding connect/disconnect boilerplate for your classes.
template <typename T>
class SlotRegister {
public:
typedef std::function<T> FunctionType;
typedef Signal<T> SignalType;
typedef std::shared_ptr<Signal<T>> SharedSignalType;
SlotRegister(Slot<T> &a_slot) :
slot(a_slot){
}
//no protection against duplicates
std::shared_ptr<Signal<T>> connect(std::function<T> a_callback){
return slot.connect(a_callback);
}
//duplicate shared_ptr's will not be added
bool connect(std::shared_ptr<Signal<T>> a_value){
return slot.connect(a_value);
}
void disconnect(std::shared_ptr<Signal<T>> a_value){
slot.disconnect(a_value);
}
private:
Slot<T> &slot;
};
}
#endif
Supplimental scopeGuard.hpp:
#ifndef _MV_SCOPEGUARD_H_
#define _MV_SCOPEGUARD_H_
//Lifted from Alexandrescu's ScopeGuard11 talk.
namespace MV {
template <typename Fun>
class ScopeGuard {
Fun f_;
bool active_;
public:
ScopeGuard(Fun f)
: f_(std::move(f))
, active_(true) {
}
~ScopeGuard() { if(active_) f_(); }
void dismiss() { active_ = false; }
ScopeGuard() = delete;
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&& rhs)
: f_(std::move(rhs.f_))
, active_(rhs.active_) {
rhs.dismiss();
}
};
template<typename Fun>
ScopeGuard<Fun> scopeGuard(Fun f){
return ScopeGuard<Fun>(std::move(f));
}
namespace ScopeMacroSupport {
enum class ScopeGuardOnExit {};
template <typename Fun>
MV::ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun&& fn) {
return MV::ScopeGuard<Fun>(std::forward<Fun>(fn));
}
}
#define SCOPE_EXIT \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= MV::ScopeMacroSupport::ScopeGuardOnExit() + [&]()
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __COUNTER__)
#else
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __LINE__)
#endif
}
#endif
An example application making use of my library:
#include <iostream>
#include <string>
#include "signal.hpp"
class Observed {
private:
//Note: This is private to ensure not just anyone can spawn a signal
MV::Slot<void (int)> onChangeSlot;
public:
typedef MV::Slot<void (int)>::SharedSignalType ChangeEventSignal;
//SlotRegister is public, users can hook up signals to onChange with this value.
MV::SlotRegister<void (int)> onChange;
Observed():
onChange(onChangeSlot){ //Here is where the binding occurs
}
void change(int newValue){
onChangeSlot(newValue);
}
};
class Observer{
public:
Observer(std::string a_name, Observed &a_observed){
connection = a_observed.onChange.connect([=](int value){
std::cout << a_name << " caught changed value: " << value << std::endl;
});
}
private:
Observed::ChangeEventSignal connection;
};
int main(){
Observed observed;
Observer observer1("o[1]", observed);
{
Observer observer2("o[2]", observed);
observed.change(1);
}
observed.change(2);
}
Output of the above would be:
o[1] caught changed value: 1
o[2] caught changed value: 1
o[1] caught changed value: 2
As you can see, the slot disconnects dead signals automatically.
Here's what I came up with.
This assumes no need to aggregate results from the listeners of a broadcast signal.
Also, the "slot" or Signal::Listener is the owner of the callback.
This ought to live with the object that your (I'm guessing...) lambda is probably capturing so that when that object goes out of scope, so does the callback, which prevents it from being called anymore.
You could use methods described in other answers as well to store the Listener owner objects in a way you can lookup.
template <typename... FuncArgs>
class Signal
{
using fp = std::function<void(FuncArgs...)>;
std::forward_list<std::weak_ptr<fp> > registeredListeners;
public:
using Listener = std::shared_ptr<fp>;
Listener add(const std::function<void(FuncArgs...)> &cb) {
// passing by address, until copy is made in the Listener as owner.
Listener result(std::make_shared<fp>(cb));
registeredListeners.push_front(result);
return result;
}
void raise(FuncArgs... args) {
registeredListeners.remove_if([&args...](std::weak_ptr<fp> e) -> bool {
if (auto f = e.lock()) {
(*f)(args...);
return false;
}
return true;
});
}
};
usage
Signal<int> bloopChanged;
// ...
Signal<int>::Listener bloopResponse = bloopChanged.add([](int i) { ... });
// or
decltype(bloopChanged)::Listener bloopResponse = ...
// let bloopResponse go out of scope.
// or re-assign it
// or reset the shared_ptr to disconnect it
bloopResponse.reset();
I have made a gist for this too, with a more in-depth example:
https://gist.github.com/johnb003/dbc4a69af8ea8f4771666ce2e383047d
I have had a go at this myself also. My efforts can be found at this gist, which will continue to evolve . . .
https://gist.github.com/4172757
I use a different style, more similar to the change notifications in JUCE than BOOST signals. Connection management is done using some lambda syntax that does some capture by copy. It is working well so far.