I am trying to achieve the following code pattern.
struct Worker {
void update(/* function pointer */) {
for(unsigned int i = 0; i < 10; i++) {
/* function execution */
}
}
}
template <typename t_derive>
struct BaseCrtp {
void method1() {
static_cast<t_derive*>(this)->method1();
}
void method2() {
static_cast<t_derive*>(this)->worker.update(/*fptr of Derived1::method2*/);
}
}
struct Derived1 : public BaseCrtp<Derived1> {
Worker worker;
void method1() {
std::cout << "Derived1::method1" << std::endl;
}
void method2() {
std::cout << "Derived1::method2" << std::endl;
}
}
I would like to call Derived1's method2 in the instance of Worker::update. How can I define a function pointer that I can inject into the update function.
struct Worker {
void update(/* function pointer */) {
.....
Make Worker::update a template member-function:
struct Worker {
template<typename Func>
void update(Func&& func) {
.....
or use std::function:
struct Worker {
void update(std::function<void()> func) {
.....
Then pass the callback via a lambda in your BaseCrtp<>::method2 as below:
void method2() {
static_cast<t_derive*>(this)->worker.update(
[this]{ static_cast<t_derive*>(this)->method2(); }
);
}
Full example:
#include <iostream>
#include <functional>
struct Worker {
template<typename Func>
void update(Func&& func) {
for(unsigned int i = 0; i < 10; i++) {
func();
}
}
//alternatively....
//
//void update(std::function<void()> func) {
// for(unsigned int i = 0; i < 10; i++) {
// func();
// }
//}
};
template <typename t_derive>
struct BaseCrtp {
void method1() {
static_cast<t_derive*>(this)->method1();
}
void method2() {
static_cast<t_derive*>(this)->worker.update(
[this]{ static_cast<t_derive*>(this)->method2(); }
);
}
};
struct Derived1 : public BaseCrtp<Derived1> {
Worker worker;
void method1() {
std::cout << "Derived1::method1" << std::endl;
}
void method2() {
std::cout << "Derived1::method2" << std::endl;
}
};
template<typename T>
void process(BaseCrtp<T>& t){
t.method2();
}
int main(){
Derived1 d1;
process(d1);
}
As seen here or here (std::function alternative).
As Martin Bonner suggested I think you could make use of Worker template with type template parameter containing Derived class and non-type template parameter with a pointer to the method you would like to invoke. This can be done as follows:
template <class T, void (T::*)(void)>
struct Worker {
void update(T *t) {
t->method2();
}
};
struct Foo {
void method2() { }
Worker<Foo, &Foo::method2> worker;
};
int main() {
Foo foo;
foo.worker.update(&foo);
}
[online demo]
This when using compiler optimization should most probably be inlined now which is actually the point of using crtp in a first place:
[godbolt]
I have a template method inside a template class.
I read that a method can not be specialized without specialize the class before.
But I want to factorize some of theses methods, is it possible ?
Example :
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num> class A {
private:
num n;
public:
template<typename type>
void multiplyBy(); // by 1 if <int> or 1,5 if <float>
}; // A
template<> template<> void A<One>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
template<> template<> void A<One>::multiplyBy<float>() {
std::cout << 1.5*n.number << std::endl;
}
template<> template<> void A<Two>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
template<> template<> void A<Two>::multiplyBy<float>() {
std::cout << 1.5*n.number << std::endl;
}
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
A stackoverflow related question : C++ specialization of template function inside template class
In particular this comment : C++ specialization of template function inside template class
Have I to deduct than there is no way to factorize multiplyBy(), for one for int and an other for float ?
As english is not my natural language maybe I miss something simple, maybe a workaround with partial-specialization.
Edit : put A::n in private to match even better my problem.
You might use tag dispatching:
#include <iostream>
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num>
class A {
public:
num n;
private:
template<typename> struct Tag {};
void multiplyBy(Tag<int>) {
std::cout << 1.0*n.number << std::endl;
}
void multiplyBy(Tag<float>) {
std::cout << 1.5*n.number << std::endl;
}
public:
template<typename type>
void multiplyBy() {
multiplyBy(Tag<type>());
}
};
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
But I want to factorize some of theses methods, is it possible ?
You probably know that you cannot use:
template<> template<> void A<One>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
without specializing A<One>.
You can do something along the lines of:
#include <iostream>
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num, typename type = int> struct MultiplyBy {
static void doit(num n)
{
std::cout << 1.0*n.number << std::endl;
}
};
template<typename num> struct MultiplyBy<num, float> {
static void doit(num n)
{
std::cout << 1.5*n.number << std::endl;
}
};
template<typename num> class A {
public:
num n;
template<typename type>
void multiplyBy()
{
MultiplyBy<num, type>::doit(n);
}
};
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
How does one provide a unified interface to sets of functions, that are used in the same way? To illustrate, please look at the set of given library functions:
/* existing library functions */
/* the signatures are different: some return int, some float */
/* set of input related functions */
int getInputValue() { return 42; }
size_t getInputSize() { return 1; }
/* set of output related functions */
int getOutputValue() { return 21; }
size_t getOutputSize() { return 1; }
/* set of parameter related functions */
float getParameterValue() { return 3.14; }
size_t getParameterSize() { return 1; }
and assume they are used in the same way:
if (getSize() > 0) {
T value = getValue()
A) What is a good way to provide getSize() and getValue()?
I first though that Template Method Pattern is what I want, but I couldn't apply it, because in contrast to the Worker in the Template Method Pattern, my functions have different signatures.
So what I did instead:
/* I want to provide a uniform interface */
/* the specific part of inputs, outputs and parameters is in the traits */
struct input_traits {
typedef int value_type;
static int getValue() { return getInputValue(); }
static size_t getSize() { return getInputSize(); }
};
struct output_traits {
typedef int value_type;
static int getValue() { return getOutputValue(); }
static size_t getSize() { return getOutputSize(); }
};
struct parameter_traits {
typedef float value_type;
static float getValue() { return getParameterValue(); }
static size_t getSize() { return getParameterSize(); }
};
/* the common part (they are used in the same way) is in the Helper */
template<typename traits>
class CommonUsage {
public:
void use()
{
if (traits::getSize() > 0) {
typename traits::value_type value = traits::getValue();
}
}
};
int main()
{
CommonUsage<input_traits>().use();
CommonUsage<output_traits>().use();
CommonUsage<parameter_traits>().use();
}
B) Is this a good approach?
A. If i understood your question correctly you should use an abstract class.
Look at the next code, it essentially does the same as your code.
This is how i would do it.
#include <iostream>
template <typename value_type>
class Traits {
public:
virtual value_type getValue() const = 0;
virtual size_t getSize() const = 0;
virtual ~Traits() { }
};
class input_traits: public Traits <int>{
public:
virtual int getValue() const {
return 42;
}
virtual size_t getSize() const {
return 1;
}
};
class parameter_traits: public Traits <double>{
public:
virtual double getValue() const {
return 3.14;
}
virtual size_t getSize() const {
return 1;
}
};
class CommonUsage {
public:
template <typename value_type>
void use(const Traits<value_type>& traitsObject) {
if (traitsObject.getSize() > 0) {
std::cout << traitsObject.getValue();
}
}
};
int main() {
CommonUsage().use(parameter_traits());
return 0;
}
As an alternative to user's answer (this time using template specialization) is:
template <class T>
struct traits {
T getValue() const { throw std::runtime_exception("..."); }
size_t getSize() const { return 0; }
};
template <>
struct traits<int> {
int getValue() const { return 42; }
size_t getSize() const { return 1; }
};
template <>
struct traits<float> {
int getValue() const { return 3.145; }
size_t getSize() const { return 1; }
};
// do template aliasing
using input_traits = traits<int>;
using parameter_traits = traits<float>;
struct CommonUsage {
template <typename T>
static void use(const traits<T> &traits) {
if (traits.getSize() > 0)
std::cout << traits.getValue() << std::endl;
}
};
int main(int arg, char **argv) {
CommonUsage::use(input_traits());
CommonUsage::use(parameter_traits());
}
There are advantages/disadvantages to both approaches. If you use template specialization, you don't pay the overhead of virtual methods.
Intro:
I'm coding in VS2010 basic calculator based on FSM patter. So, I need action map.
How correctly initialize a static two dimensional array of pointers to functions in C++?
I've already tried
static void (*action_map[])() = {A, pA}; //one dimension for example
or
static void (*action_map[])() = {&A, &pA};
and many others doesn't work.
ADDED
Everything should be done inside class.
Example below doesn't work for me
public class A {
public:
void func1() { cout << "func1\n"; }
void func2() { cout << "func2\n"; }
void func3() { cout << "func3\n"; }
void func4() { cout << "func4\n"; }
typedef void (*function_t)();
function_t function_array[2][2];
A();
};
A::A()
{
function_array[2][2] = { { func1, func2}, { func3, func4 } };
};
int main(array<System::String ^> ^args)
{
A * tst = new A();
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
tst->function_array[i][j]();
}
}
return 0;
}
Please point what exactly I did wrong.
If your compiler supports C++11 initialiser lists, then you just need do drop the spurious array sizes in your assignment.
A::A()
{
function_array = { { func1, func2}, { func3, func4 } };
}
Or better still, initialise it directly, rather than assigning after default-initialisation:
A::A() : function_array { { func1, func2}, { func3, func4 } }
{}
If your compiler doesn't support C++11, you'll need to assign them by hand:
A::A()
{
function_array[0][0] = func1;
function_array[0][1] = func2;
function_array[1][0] = func3;
function_array[1][1] = func4;
}
You'll also need to make the functions static in order to store simple function pointers to them; if they have to be non-static members, then you'll need to either store member-function pointers and call them with a class instance, or store std::function objects, created using std::bind (or their Boost equivalents if you don't have C++11).
Note the type 'function_t' has changed:
class A
{
public:
void func1() { cout << "func1()\n"; }
void func2() { cout << "func2()\n"; }
void func3() { cout << "func3()\n"; }
void func4() { cout << "func4()\n"; }
typedef void (A::*function_t)();
static const function_t function_array[2][2];
};
const A::function_t A::function_array[2][2] = { { &A::func1, &A::func2 },
{ &A::func3, &A::func4 }
};
// Example use.
A my_a;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
std::mem_fn(A::function_array[i][j])(my_a);
}
}
If the array 'function_array' is changeable between class instances then a 'static const' is not appropriate and it must be populated in the constructor.
Both of them are fine if A and pA are the name of functions taking no arguments and returning a void type.
Since you're using MSVS2010 which has implemented many C++11 features, how about doing this:
void f1() {}
void f2() {}
void f3() {}
void f4() {}
std::vector<std::function<void()>> action_map = {f1, f2, f3, f4};
for(size_t i = 0 ; i < action_map.size(); ++i)
{
action_map[i](); //invoke action!
}
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?