Is it possible to implement events in C++? - c++

I wanted to implement a C# event in C++ just to see if I could do it. I got stuck, I know the bottom is wrong but what I realize my biggest problem is...
How do I overload the () operator to be whatever is in T, in this case int func(float)? I can't? Can I? Can I implement a good alternative?
#include <deque>
using namespace std;
typedef int(*MyFunc)(float);
template<class T>
class MyEvent
{
deque<T> ls;
public:
MyEvent& operator +=(T t)
{
ls.push_back(t);
return *this;
}
};
static int test(float f){return (int)f; }
int main(){
MyEvent<MyFunc> e;
e += test;
}

If you can use Boost, consider using Boost.Signals2, which provides signals-slots/events/observers functionality. It's straightforward and easy to use and is quite flexible. Boost.Signals2 also allows you to register arbitrary callable objects (like functors or bound member functions), so it's more flexible, and it has a lot of functionality to help you manage object lifetimes correctly.
If you are trying to implement it yourself, you are on the right track. You have a problem, though: what, exactly, do you want to do with the values returned from each of the registered functions? You can only return one value from operator(), so you have to decide whether you want to return nothing, or one of the results, or somehow aggregate the results.
Assuming we want to ignore the results, it's quite straightforward to implement this, but it's a bit easier if you take each of the parameter types as a separate template type parameter (alternatively, you could use something like Boost.TypeTraits, which allows you to easily dissect a function type):
template <typename TArg0>
class MyEvent
{
typedef void(*FuncPtr)(TArg0);
typedef std::deque<FuncPtr> FuncPtrSeq;
FuncPtrSeq ls;
public:
MyEvent& operator +=(FuncPtr f)
{
ls.push_back(f);
return *this;
}
void operator()(TArg0 x)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(x);
}
};
This requires the registered function to have a void return type. To be able to accept functions with any return type, you can change FuncPtr to be
typedef std::function<void(TArg0)> FuncPtr;
(or use boost::function or std::tr1::function if you don't have the C++0x version available). If you do want to do something with the return values, you can take the return type as another template parameter to MyEvent. That should be relatively straightforward to do.
With the above implementation, the following should work:
void test(float) { }
int main()
{
MyEvent<float> e;
e += test;
e(42);
}
Another approach, which allows you to support different arities of events, would be to use a single type parameter for the function type and have several overloaded operator() overloads, each taking a different number of arguments. These overloads have to be templates, otherwise you'll get compilation errors for any overload not matching the actual arity of the event. Here's a workable example:
template <typename TFunc>
class MyEvent
{
typedef typename std::add_pointer<TFunc>::type FuncPtr;
typedef std::deque<FuncPtr> FuncPtrSeq;
FuncPtrSeq ls;
public:
MyEvent& operator +=(FuncPtr f)
{
ls.push_back(f);
return *this;
}
template <typename TArg0>
void operator()(TArg0 a1)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(a1);
}
template <typename TArg0, typename TArg1>
void operator()(const TArg0& a1, const TArg1& a2)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(a1, a2);
}
};
(I've used std::add_pointer from C++0x here, but this type modifier can also be found in Boost and C++ TR1; it just makes it a little cleaner to use the function template since you can use a function type directly; you don't have to use a function pointer type.) Here's a usage example:
void test1(float) { }
void test2(float, float) { }
int main()
{
MyEvent<void(float)> e1;
e1 += test1;
e1(42);
MyEvent<void(float, float)> e2;
e2 += test2;
e2(42, 42);
}

You absolutely can. James McNellis has already linked to a complete solution, but for your toy example we can do the following:
#include <deque>
using namespace std;
typedef int(*MyFunc)(float);
template<typename F>
class MyEvent;
template<class R, class Arg>
class MyEvent<R(*)(Arg)>
{
typedef R (*FuncType)(Arg);
deque<FuncType> ls;
public:
MyEvent<FuncType>& operator+=(FuncType t)
{
ls.push_back(t);
return *this;
}
void operator()(Arg arg)
{
typename deque<FuncType>::iterator i = ls.begin();
typename deque<FuncType>::iterator e = ls.end();
for(; i != e; ++i) {
(*i)(arg);
}
}
};
static int test(float f){return (int)f; }
int main(){
MyEvent<MyFunc> e;
e += test;
e(2.0);
}
Here I've made use of partial specialization to tease apart the components of the function pointer type to discover the argument type. boost.signals does this and more, leveraging features such as type erasure, and traits to determine this information for non-function pointer typed callable objects.
For N arguments there are two approaches. The "easy' way, that was added for C++0x, is leveraging variadic templates and a few other features. However, we've been doing this since before that features was added, and I don't know which compilers if any, support variadic templates yet. So we can do it the hard way, which is, specialize again:
template<typename R, typename Arg0, typename Arg1>
class MyEvent<R(*)(Arg0, Arg1)>
{
typedef R (*FuncType)(Arg0, Arg1);
deque<FuncType> ls;
...
void operatror()(Arg0 a, Arg1)
{ ... }
MyEvent<FuncType>& operator+=(FuncType f)
{ ls.push_back(f); }
...
};
THis gets tedious of course which is why have libraries like boost.signals that have already banged it out (and those use macros, etc. to relieve some of the tedium).
To allow for a MyEvent<int, int> style syntax you can use a technique like the following
struct NullEvent;
template<typename A = NullEvent, typename B = NullEvent, typename C = NullEvent>
class HisEvent;
template<>
struct HisEvent<NullEvent,NullEvent,NullEvent>
{ void operator()() {} };
template<typename A>
struct HisEvent<A,NullEvent,NullEvent>
{ void operator()(A a) {} };
template<typename A, typename B>
struct HisEvent<A, B, NullEvent>
{
void operator()(A a, B b) {}
};
template<typename A, typename B, typename C>
struct HisEvent
{
void operator()(A a, B b, C c)
{}
};
static int test(float f){return (int)f; }
int main(){
MyEvent<MyFunc> e;
e += test;
e(2.0);
HisEvent<int> h;
HisEvent<int, int> h2;
}
The NullEvent type is used as a placeholder and we again use partial specialization to figure out the arity.

EDIT: Added thread safe implementation, based on this answer. Many fixes and performance improvements
This is my version, improving James McNellis' one by adding: operator-=, variadic template to support any ariety of the stored callable objects, convenience Bind(func, object) and Unbind(func, object) methods to easily bind objects and instance member functions, assignment operators and comparison with nullptr. I moved away from using std::add_pointer to just use std::function which in my attempts it's more flexible (accepts both lambdas and std::function). Also I moved to use std::vector for faster iteration and removed returning *this in the operators, since it doesn't look to be very safe/useful anyway. Still missing from C# semantics: C# events can't be cleared from outside the class where they are declared (would be easy to add this by state friendship to a templatized type).
It follows the code, feedback is welcome:
#pragma once
#include <typeinfo>
#include <functional>
#include <stdexcept>
#include <memory>
#include <atomic>
#include <cstring>
template <typename TFunc>
class Event;
template <class RetType, class... Args>
class Event<RetType(Args ...)> final
{
private:
typedef typename std::function<RetType(Args ...)> Closure;
struct ComparableClosure
{
Closure Callable;
void *Object;
uint8_t *Functor;
int FunctorSize;
ComparableClosure(const ComparableClosure &) = delete;
ComparableClosure() : Object(nullptr), Functor(nullptr), FunctorSize(0) { }
ComparableClosure(Closure &&closure) : Callable(std::move(closure)), Object(nullptr), Functor(nullptr), FunctorSize(0) { }
~ComparableClosure()
{
if (Functor != nullptr)
delete[] Functor;
}
ComparableClosure & operator=(const ComparableClosure &closure)
{
Callable = closure.Callable;
Object = closure.Object;
FunctorSize = closure.FunctorSize;
if (closure.FunctorSize == 0)
{
Functor = nullptr;
}
else
{
Functor = new uint8_t[closure.FunctorSize];
std::memcpy(Functor, closure.Functor, closure.FunctorSize);
}
return *this;
}
bool operator==(const ComparableClosure &closure)
{
if (Object == nullptr && closure.Object == nullptr)
{
return Callable.target_type() == closure.Callable.target_type();
}
else
{
return Object == closure.Object && FunctorSize == closure.FunctorSize
&& std::memcmp(Functor, closure.Functor, FunctorSize) == 0;
}
}
};
struct ClosureList
{
ComparableClosure *Closures;
int Count;
ClosureList(ComparableClosure *closures, int count)
{
Closures = closures;
Count = count;
}
~ClosureList()
{
delete[] Closures;
}
};
typedef std::shared_ptr<ClosureList> ClosureListPtr;
private:
ClosureListPtr m_events;
private:
bool addClosure(const ComparableClosure &closure)
{
auto events = std::atomic_load(&m_events);
int count;
ComparableClosure *closures;
if (events == nullptr)
{
count = 0;
closures = nullptr;
}
else
{
count = events->Count;
closures = events->Closures;
}
auto newCount = count + 1;
auto newClosures = new ComparableClosure[newCount];
if (count != 0)
{
for (int i = 0; i < count; i++)
newClosures[i] = closures[i];
}
newClosures[count] = closure;
auto newEvents = ClosureListPtr(new ClosureList(newClosures, newCount));
if (std::atomic_compare_exchange_weak(&m_events, &events, newEvents))
return true;
return false;
}
bool removeClosure(const ComparableClosure &closure)
{
auto events = std::atomic_load(&m_events);
if (events == nullptr)
return true;
int index = -1;
auto count = events->Count;
auto closures = events->Closures;
for (int i = 0; i < count; i++)
{
if (closures[i] == closure)
{
index = i;
break;
}
}
if (index == -1)
return true;
auto newCount = count - 1;
ClosureListPtr newEvents;
if (newCount == 0)
{
newEvents = nullptr;
}
else
{
auto newClosures = new ComparableClosure[newCount];
for (int i = 0; i < index; i++)
newClosures[i] = closures[i];
for (int i = index + 1; i < count; i++)
newClosures[i - 1] = closures[i];
newEvents = ClosureListPtr(new ClosureList(newClosures, newCount));
}
if (std::atomic_compare_exchange_weak(&m_events, &events, newEvents))
return true;
return false;
}
public:
Event()
{
std::atomic_store(&m_events, ClosureListPtr());
}
Event(const Event &event)
{
std::atomic_store(&m_events, std::atomic_load(&event.m_events));
}
~Event()
{
(*this) = nullptr;
}
void operator =(const Event &event)
{
std::atomic_store(&m_events, std::atomic_load(&event.m_events));
}
void operator=(nullptr_t nullpointer)
{
while (true)
{
auto events = std::atomic_load(&m_events);
if (!std::atomic_compare_exchange_weak(&m_events, &events, ClosureListPtr()))
continue;
break;
}
}
bool operator==(nullptr_t nullpointer)
{
auto events = std::atomic_load(&m_events);
return events == nullptr;
}
bool operator!=(nullptr_t nullpointer)
{
auto events = std::atomic_load(&m_events);
return events != nullptr;
}
void operator +=(Closure f)
{
ComparableClosure closure(std::move(f));
while (true)
{
if (addClosure(closure))
break;
}
}
void operator -=(Closure f)
{
ComparableClosure closure(std::move(f));
while (true)
{
if (removeClosure(closure))
break;
}
}
template <typename TObject>
void Bind(RetType(TObject::*function)(Args...), TObject *object)
{
ComparableClosure closure;
closure.Callable = [object, function](Args&&...args)
{
return (object->*function)(std::forward<Args>(args)...);
};
closure.FunctorSize = sizeof(function);
closure.Functor = new uint8_t[closure.FunctorSize];
std::memcpy(closure.Functor, (void*)&function, sizeof(function));
closure.Object = object;
while (true)
{
if (addClosure(closure))
break;
}
}
template <typename TObject>
void Unbind(RetType(TObject::*function)(Args...), TObject *object)
{
ComparableClosure closure;
closure.FunctorSize = sizeof(function);
closure.Functor = new uint8_t[closure.FunctorSize];
std::memcpy(closure.Functor, (void*)&function, sizeof(function));
closure.Object = object;
while (true)
{
if (removeClosure(closure))
break;
}
}
void operator()()
{
auto events = std::atomic_load(&m_events);
if (events == nullptr)
return;
auto count = events->Count;
auto closures = events->Closures;
for (int i = 0; i < count; i++)
closures[i].Callable();
}
template <typename TArg0, typename ...Args2>
void operator()(TArg0 a1, Args2... tail)
{
auto events = std::atomic_load(&m_events);
if (events == nullptr)
return;
auto count = events->Count;
auto closures = events->Closures;
for (int i = 0; i < count; i++)
closures[i].Callable(a1, tail...);
}
};
I tested it with this:
#include <iostream>
using namespace std;
class Test
{
public:
void foo() { cout << "Test::foo()" << endl; }
void foo1(int arg1, double arg2) { cout << "Test::foo1(" << arg1 << ", " << arg2 << ") " << endl; }
};
class Test2
{
public:
Event<void()> Event1;
Event<void(int, double)> Event2;
void foo() { cout << "Test2::foo()" << endl; }
Test2()
{
Event1.Bind(&Test2::foo, this);
}
void foo2()
{
Event1();
Event2(1, 2.2);
}
~Test2()
{
Event1.Unbind(&Test2::foo, this);
}
};
int main(int argc, char* argv[])
{
(void)argc;
(void)argv;
Test2 t2;
Test t1;
t2.Event1.Bind(&Test::foo, &t1);
t2.Event2 += [](int arg1, double arg2) { cout << "Lambda(" << arg1 << ", " << arg2 << ") " << endl; };
t2.Event2.Bind(&Test::foo1, &t1);
t2.Event2.Unbind(&Test::foo1, &t1);
function<void(int, double)> stdfunction = [](int arg1, double arg2) { cout << "stdfunction(" << arg1 << ", " << arg2 << ") " << endl; };
t2.Event2 += stdfunction;
t2.Event2 -= stdfunction;
t2.foo2();
t2.Event2 = nullptr;
}

That is possible, but not with your current design. The problem lies with the fact that the callback function signature is locked into your template argument. I don't think you should try to support this anyways, all callbacks in the same list should have the same signature, don't you think?

Related

using template arguments to specify policy

I got to know that we can also pass template arguments to choose which function should execute. I found them good alternative to function pointers since function pointers has run time cost but template parameters does not. Also, template parameters can be made inline whereas function pointers are not.
Alright then, this is what I wrote to depict my understanding on it. I came close but missing some minor detail somewhere.
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.length()) && (i < str2.length()); ++i) {
if (C::eq(str1[i], str2[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<String<std::string>, Cmp1<std::string> >(s, t);
// compare(s, t);
}
Details of the code:
I have an class String, which take an parameter and create member function of that type.
I have an compare function, which takes two String& arguments. Comparison function is passed to it.
Cmp1 and Cmp2 are two compare functions.
compare<String<std::string>, Cmp1<std::string> >(s, t);
does not get compile here. I tried some other ways to call but in vain.
Looks like you want something like that:
#include <iostream>
#include <string>
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.str.length()) && (i < str2.str.length()); ++i) {
if (C::eq(str1.str[i], str2.str[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
public:
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
public:
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<std::string, Cmp1<char> >(s, t);
// compare(s, t);
}
code
Explanations:
You already have String in definition of compare, you need to just send T which is std::string in your case.
You are trying to go through entire std::string, in compare, so, now your code compiles.
You calling cmp on str[index], that is actually char, so you need to call cmp with char template argument.

Using same template for regular pointer and shared pointer

This one does not work. I wanted to reuse the template that I made for regular pointer. How can I use the same template for std::shared_ptr
class Base
{
public:
int getVal() { return 0; }
};
template <class Type>
bool writeRecordForSet(std::vector<Type> entityPtr)
{
if (entityPtr.size() == 0) return true;
//...
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
Type enPtr = *iter;
int myval = enPtr->getVal();
}
return true;
}
int main()
{
std::vector<std::shared_ptr<Base>> vec_shared;
std::vector<int*> vec_intp;
std::vector<std::unique_ptr<Base>> vec_unique_ptr;
writeRecordForSet(vec_shared);
writeRecordForSet(vec_intp);
writeRecordForSet(vec_unique_ptr);
}
You cannot copy a std::unique_ptr<>, nor a std::vector<std::unique_ptr<>>, so don't try that, but take the argument by reference (which you should to anyway; also use a range-based for loop for clarity)
template <class Type>
bool writeRecordForSet(std::vector<Type> const&entityPtr)
{
if (entityPtr.size() == 0) return true;
for(const auto&enPtr : entityPtr) {
auto myval = enPtr->getVal();
/* ... */
}
return true;
}
Of course, this will fail to compile if called for a Type that does not allow for Type::getVal() (such as your vector<int*> example). If you want your function to work for Types that don't have such a getter, you can use a getter adaptation, i.e.
template<typename T>
inline auto getVal(T const&x) { return T::getVal(); }
inline int getVal(int*x) { return *x; }
Problem 1
bool writeRecordForSet(std::vector<Type> entityPtr) { ... }
is a problem when the argument is of type std::unique_ptr since they cannot be copy constructed.
Change that to use a reference:
bool writeRecordForSet(std::vector<Type>& entityPtr) { ... }
or
bool writeRecordForSet(std::vector<Type> const& entityPtr) { ... }
Problem 2
In the function, you are assuming that the core object is of type Base.
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
Type enPtr = *iter;
// Assuming that enPtr is a Base*, or shared_ptr<Base>, or unique_ptr<Base>
int myval = enPtr->getVal();
}
If you use
std::vector<Base*> vec_intp;
instead of
std::vector<int*> vec_intp;
it will work.
You can add getVal adaptor function to make it work and then write multiple overloads for your int*, shared_ptr<Base>, unique_ptr<Base>.
For example, getVal for int* could be as simple as:
int getVal(int*& p)
{
return *p;
}
And then your writeRecordForSet should call getVal to get int value.
Full example:
#include <vector>
#include <memory>
using namespace std;
class Base
{
public:
int getVal() { return 0; }
};
int getVal(shared_ptr<Base>& p)
{
return p->getVal();
}
int getVal(unique_ptr<Base>& p)
{
return p->getVal();
}
int getVal(int*& p)
{
return *p;
}
template <class Type>
bool writeRecordForSet(std::vector<Type>& entityPtr)
{
if (entityPtr.size() == 0)
return true;
//...
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
int myval = getVal(*iter);
}
return true;
}
int main()
{
std::vector<std::shared_ptr<Base>> vec_shared;
std::vector<int*> vec_intp;
std::vector<std::unique_ptr<Base>> vec_unique_ptr;
writeRecordForSet(vec_shared);
writeRecordForSet(vec_intp);
writeRecordForSet(vec_unique_ptr);
}

Binding a std::function to the same function of a different object instance

Is it possible to rebind a std::function to point to the same function but with a different object instance?
Say if I have an object that has a std::function that is bound to another function, but if that object was copied to another instance, I'd like to rebind the std::function to that new instance instead of the old instance.
#include "stdafx.h"
#include <iostream>
#include <functional>
class EventHandler
{
public:
int Num;
std::function<int()> OnEvent;
EventHandler (int inNum)
{
Num = inNum;
}
EventHandler (const EventHandler& other)
{
Num = other.Num;
OnEvent = other.OnEvent; //TODO: Need some way to redirect the std::function to the new instance rather than having the delegate point to the original object's handler.
}
int HandleEvent ()
{
return Num;
}
};
int main()
{
EventHandler a(4);
a.OnEvent = std::bind(&EventHandler::HandleEvent, a);
EventHandler b(a);
b.Num = 5;
//Uncommenting the line below is a manual way of redirecting event handler to the new instance.
//b.OnEvent = std::bind(&EventHandler::HandleEvent, b);
int aResult = a.OnEvent();
int bResult = b.OnEvent();
//This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler.
std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n';
return 0;
}
I'm open to having a wrapper of the std::function to store additional information.
The following code introduced a binding_function<R(Args...)>, which is called like function<R()>, and arguments can be rebind anytime after it constructed (assuming it was not nullptr).
#include <functional>
#include <tuple>
#include <utility>
#include <memory>
#include <iostream>
template <typename T>
class binding_function;
template <typename R, typename... Args>
class binding_function<R(Args...)> : std::function<R()>
{
using base_function = std::function<R(Args...)>;
using binded_function = std::function<R()>;
base_function base;
public:
binding_function() = default;
template <typename BaseF, typename... TArgs>
binding_function(BaseF&& f, TArgs&&... args)
: base(std::forward<BaseF>(f)) {
rebind(std::forward<TArgs>(args)...);
}
template <typename... TArgs>
void rebind(TArgs&&... args)
{
static_cast<binded_function&>(*this) =
std::bind(base, std::forward<TArgs>(args)...);
}
using binded_function::operator();
};
class EventHandler
{
public:
// change type of OnEvent to binding_function
binding_function<int(EventHandler)> OnEvent;
// others remain the same
};
int main()
{
EventHandler a(4);
// first binding
a.OnEvent = {&EventHandler::HandleEvent, a};
EventHandler b(a);
b.Num = 5;
b.OnEvent.rebind(b); // rebinding
int aResult = a.OnEvent();
int bResult = b.OnEvent();
//This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler.
std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n';
return 0;
}
What your event handler does should depend on which instance it is called on. Hence, logically, the correct way of solving the problem is providing the instance as a parameter to the handler function, e.g.
#include <iostream>
#include <functional>
class EventHandler
{
private:
std::function<int(EventHandler &)> handlingFunction;
public:
int Num;
EventHandler (int inNum)
: handlingFunction ([] (EventHandler &) -> int { throw 0; })
, Num (inNum)
{ }
void SetHandlingFunction (std::function<int(EventHandler &)> f) {
handlingFunction = f;
}
// for convenience, if the handling function is a member
void SetHandlingFunction (int EventHandler::*mf ()) {
handlingFunction =
[mf] (EventHandler & myself) -> int { return myself.*mf (); }
;
}
int OnEvent () {
return handlingFunction (*this);
}
int HandleEvent ()
{
return Num;
}
};
int main()
{
EventHandler a(4);
a.SetHandlingFunction ( [] (EventHandler & h) -> int { return h.HandleEvent (); } );
// or
a.SetHandlingFunction (&EventHandler::HandleEvent);
EventHandler b(a);
b.Num = 5;
int aResult = a.OnEvent();
int bResult = b.OnEvent();
std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n';
return 0;
}
Of course, if your handling function always is a member function, you can simply replace the std::function by a pointer-to-member-function.
Note that you should properly initialize the handlingFunction member in the constructor of your EventHandler class, e.g. by setting it to a dummy function.
I extended user1887915's answer to allow functions with parameters:
#include <functional>
#include <tuple>
#include <utility>
#include <memory>
#include <iostream>
template <typename T>
class binding_function;
template <typename R, typename... Args, typename SelfType>
class binding_function<R(SelfType, Args...)> : std::function<R(Args...)>
{
using base_function = std::function<R(SelfType, Args...)>;
using binded_function = std::function<R(Args...)>;
base_function base;
public:
binding_function() = default;
template <typename BaseF, typename... TArgs>
binding_function(BaseF&& f, SelfType t, TArgs&&... args)
: base(std::forward<BaseF>(f)) {
rebind(std::forward<SelfType>(t), std::forward<TArgs>(args)...);
}
template <typename T, typename... TArgs>
void rebind(T&& t, TArgs&&... args)
{
static_cast<binded_function&>(*this) =
std::bind(base, std::forward<SelfType>(t), std::forward<TArgs>(args)...);
}
using binded_function::operator();
};
class EventHandler
{
public:
int Num;
binding_function<int(EventHandler, int)> OnEvent;
EventHandler (int inNum)
{
Num = inNum;
}
EventHandler (const EventHandler& other)
{
Num = other.Num;
OnEvent = other.OnEvent; //TODO: Need some way to redirect the std::function to the new instance rather than having the delegate point to the original object's handler.
}
int HandleEvent (int value)
{
return Num + value;
}
};
int main()
{
EventHandler a(4);
// first binding
a.OnEvent = {&EventHandler::HandleEvent, a, std::placeholders::_1};
EventHandler b(a);
b.Num = 5;
b.OnEvent.rebind(b, std::placeholders::_1); // rebinding
int aResult = a.OnEvent(1);
int bResult = b.OnEvent(1);
//This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler.
std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n';
return 0;
}
AFAIK what you are asking is not possible, but I think there is a workaround that you can do:
class EventHandler
{
public:
int Num;
std::function<int()> OnEvent;
template <typename Func>
EventHandler (int inNum, Func on_event)
{
Num = inNum;
OnEvent = [=]() { return (this->*on_event)(); };
}
EventHandler (const EventHandler& other): EventHandler(other.Num, &EventHandler::HandleEvent) {}
int HandleEvent ()
{
return Num;
}
};
int main()
{
EventHandler a(4, &EventHandler::HandleEvent);
EventHandler b(a);
b.Num = 5;
int aResult = a.OnEvent();
int bResult = b.OnEvent();
//This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler.
std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n';
return 0;
}
This prints "aResult=4 bResult=5" as you want.
Also, I think by employing a bit more metaprogramming magic, we can try to prettify the syntax.
Let me know if this works for you.

Is there a standalone implementation of std::function?

I'm working on an embedded system, so code size is an issue. Using the standard library ups my binary size by about 60k, from 40k to 100k. I'd like to use std::function, but I can't justify it for 60k. Is there a standalone implementation that I can use, or something similar? I'm using it to implicitly cast lambdas in member functions with bound variables in c++ 11.
Here is simple implementation of std::function-like class template without inclusion of any headers. You can customize the behavior as you wish(like move/forward, empty call response, etc):
live_demo
// Scroll down for example of usage
namespace bicycle
{
template<typename Result,typename ...Args>
struct abstract_function
{
virtual Result operator()(Args... args)=0;
virtual abstract_function *clone() const =0;
virtual ~abstract_function() = default;
};
template<typename Func,typename Result,typename ...Args>
class concrete_function: public abstract_function<Result,Args...>
{
Func f;
public:
concrete_function(const Func &x)
: f(x)
{}
Result operator()(Args... args) override
{
return f(args...);
}
concrete_function *clone() const override
{
return new concrete_function{f};
}
};
template<typename Func>
struct func_filter
{
typedef Func type;
};
template<typename Result,typename ...Args>
struct func_filter<Result(Args...)>
{
typedef Result (*type)(Args...);
};
template<typename signature>
class function;
template<typename Result,typename ...Args>
class function<Result(Args...)>
{
abstract_function<Result,Args...> *f;
public:
function()
: f(nullptr)
{}
template<typename Func> function(const Func &x)
: f(new concrete_function<typename func_filter<Func>::type,Result,Args...>(x))
{}
function(const function &rhs)
: f(rhs.f ? rhs.f->clone() : nullptr)
{}
function &operator=(const function &rhs)
{
if( (&rhs != this ) && (rhs.f) )
{
auto *temp = rhs.f->clone();
delete f;
f = temp;
}
return *this;
}
template<typename Func> function &operator=(const Func &x)
{
auto *temp = new concrete_function<typename func_filter<Func>::type,Result,Args...>(x);
delete f;
f = temp;
return *this;
}
Result operator()(Args... args)
{
if(f)
return (*f)(args...);
else
return Result{};
}
~function()
{
delete f;
}
};
}
// ___________________[ Example of usage ]___________________ //
int func1(double)
{
return 1;
}
struct Functor2
{
int operator()(double)
{
return 2;
}
};
double func3(bool,int)
{
return 3.0;
}
struct Functor4
{
double operator()(bool,int)
{
return 4.0;
}
};
int main()
{
int res = 10;
{
bicycle::function<int(double)> f{func1};
res -= f(1.0);
f = Functor2{};
res -= f(2.0);
}
{
bicycle::function<double(bool,int)> f1;
f1 = func3;
bicycle::function<double(bool,int)> f2{f1};
res -= f2(true,1);
f1 = Functor4{};
f2 = f1;
res -= f2(false,2);
}
return res;
}
The 60k came from exception handling being added by the compiler, because exceptions were required for std::function. std::function only throws one exception, "bad_function_call". So I removed the code that threw the exception, now it seg faults if an empty function is called, and I saved myself 60k.

Variable user-defined parameter list in C++?

I'm looking for a simple way to create a user multi-parameter receiving function,
Here's some pseudo code
#include <iostream>
struct A {
int m_num;
};
void function(A* a, ...)
{
/* Pseudo-Code here */
for each parameter do
print a->m_num
end
}
int main()
{
A *a = new A();
A *b = new A();
A *c = new A();
a->m_num = 1;
b->m_num = 10;
c->m_num = 100;
function(a,b,c);
// delete everything
return 0;
}
I can't really use boost here, so if it's possible with standard C++ ( STL Allowed ), it would be great.
EDIT: The function parameters are heterogeneous
Old school plain C variadic arguments:
#include <cstdio>
#include <stdarg.h>
struct A {
A () : m_num (0) {}
A (int v) : m_num (v) {}
int m_num;
};
void function (A *a, ...)
{
va_list ap;
A *p = a;
va_start (ap, a);
while (p != NULL)
{
printf ("%d\n", p->m_num);
p = va_arg (ap, A*);
}
va_end (ap);
}
int main()
{
A a (1), b (10), c (100);
function (&a, &b, &c, NULL);
}
Another solution if arguments are of the same type (which is your case):
#include <cstdio>
struct A {
A () : m_num (0) {}
A (int v) : m_num (v) {}
int m_num;
};
void function (A *p, A *endp)
{
while (p != endp)
{
printf ("%d\n", p->m_num);
++p;
}
}
int main()
{
A a[3];
a[0].m_num = 1;
a[1].m_num = 10;
a[2].m_num = 100;
function (a, a + sizeof (a) / sizeof(a[0]));
}
Or even more C++-style, with iterators:
#include <cstdio>
#include <vector>
#include <list>
struct A {
A () : m_num (0) {}
A (int v) : m_num (v) {}
int m_num;
};
template <typename T>
void function (T p, T endp)
{
while (p != endp)
{
printf ("%d\n", p->m_num);
++p;
}
}
int main()
{
A a[3];
a[0].m_num = 1;
a[1].m_num = 10;
a[2].m_num = 100;
function (a, a + sizeof (a) / sizeof(a[0]));
std::vector<A> av (3);
av[0].m_num = 1;
av[1].m_num = 10;
av[2].m_num = 100;
function (av.begin (), av.end ());
std::list<A> al;
al.push_back (A (1));
al.push_back (A (10));
al.push_back (A (100));
function (al.begin (), al.end ());
}
The most straightforward way is to put your parameters into a std::vector. If they're non-homogeneous you can use a vector of boost::any or boost::variant.
Alternately design your interface like streams and use an insertion like operator/function that operators on one parameter at a time.
It would look something like this, alternately using a friend free-function.
struct A
{
int m_num;
};
struct printer
{
function& operator<<(A* a)
{
/* Pseudo-Code here */
print a->m_num
return *this;
}
};
int main()
{
A *a = new A();
A *b = new A();
A *c = new A();
a->m_num = 1;
b->m_num = 10;
c->m_num = 100;
printer function;
function << a << b << c;
// delete everything
return 0;
}
If every parameter going into function is an A, I'd do it with an array of A's, as in:
int main() {
A *abc[3];
for (int i=0;i<3;i++)
abc[i]=new A();
abc[0]->m_num=1;
abc[1]->m_num=10;
abc[2]->m_num=100;
function(abc,3);
}
void function(A *vals[],int count) {
for (int i=0;i<count;i++)
print vals[i]->m_num;
}
If you have a compiler recent enough to ship with std::tuple<> or std::tr1::tuple<>, you can do the following:
#include <cstddef>
#include <tuple>
#include <iostream>
struct A
{
int m_num;
};
template<typename T>
class function_impl
{
template<std::size_t N>
static void impl(T const& tup)
{
std::cout << std::get<N>(tup)->m_num << '\n';
}
template<std::size_t N>
struct recurse_helper
{
static void invoke(T const& tup)
{
function_impl<T>::template impl<N>(tup);
recurse_helper<N + 1u>::invoke(tup);
}
};
template<>
struct recurse_helper<std::tuple_size<T>::value>
{
static void invoke(T const&) { }
};
public:
static void invoke(T const& tup)
{
recurse_helper<0u>::invoke(tup);
}
};
template<typename T>
void function(T const& tup)
{
function_impl<T>::invoke(tup);
}
int main()
{
A* a = new A();
a->m_num = 1;
A* b = new A();
b->m_num = 10;
A* c = new A();
c->m_num = 100;
function(std::tie(a, b, c));
delete c;
delete b;
delete a;
}
Note that function actually takes a singular argument, a tuple<>, rather than multiple arguments. But, unlike any varargs-based solution, this is completely type-safe.
Also note that the implementation here would be much simpler if you could use Boost.Fusion...
As a supplement.
In C++0x, you could use variadic-template to implement your function recursively:
// Just to make the compiler happy.
template <typename T>
void function(T a) = delete;
// Base case
template <>
void function(A* a) {
printf("%d\n", a->m_num);
}
// Recursion
template <typename T, typename... Args>
void function(T a, Args... args) {
function(a);
function(args...);
}
But this will generate N functions if it accepts N parameters. Alternatively, you could use an initializer_list:
void function(std::initializer_list<A*> args) {
for (auto cit = args.begin(); cit != args.end(); ++ cit)
printf("%d\n", (*cit)->m_num);
}
but you need to call function as
function({a,b,c});
// ^ ^