xueliu
4/29/2019 - 9:12 AM

Delegate with c++11 variadic templates

#ifndef DELEGATE_HPP_INCLUDED
#define DELEGATE_HPP_INCLUDED

#include <functional>
#include <vector>

// general case
template<typename R, typename... Args>
class delegate
{
public:
    using DelegateFunc = std::function<R(Args...)>;

	template<typename U>
	delegate& operator += (const U &func)
	{
		funcs.emplace_back(std::function<R(Args...)>(func));
		return *this;
	}

	std::vector<R> operator () (Args... params)
	{
		std::vector<R> ret;
		for (auto f : funcs)
		{
			ret.push_back(f(params...));
		}
		return ret;
	}

    // template<typename U>
	// delegate& operator -= (const U &func)
	// {
	// 	funcs.remove(std::function<R(Args...)>(func));
	// 	return *this;
	// }

    // template<typename U>
    // void register(const U &func) {
    //     funcs.push_back(std::function<R(Args...)>(func));
    // }

private:
	std::vector<std::function<R(Args...)>> funcs;
};

// specialization when return type is void
template<typename... Args>
class delegate<void, Args...>
{
public:
	template<typename U>
	delegate& operator += (const U &func)
	{
		funcs.push_back(std::function<void(Args...)>(func));
		return *this;
	}

	void operator () (Args... params)
	{
		for (auto f : funcs)
		{
			f(params...);
		}
	}
private:
	std::vector<std::function<void(Args...)>> funcs;
};

#endif // DELEGATE_HPP_INCLUDED
#include <iostream>
#include "delegate.hpp"

using namespace std;

void func1(int x, int y) {
    cout << "from func1 " << x + y << endl;
}

void func2(int x, int y) {
    cout << "from func2 " << x * y << endl;
}

class A {
public:
void func1(int x, int y) {
    cout << "from class A::func1 " << x + y << endl;
}

void func2(int x, int y) {
    cout <<  "from class A::func2 " << x * y << endl;
}

};

int main()
{
    // delegate with Lambda functions without return value
	delegate<void, int, int> d1;
	d1 += [](int x, int y){cout << x + y << endl;};
	d1 += [](int x, int y){cout << x * y << endl;};
	d1(3, 5);

	delegate<int, int, int> d2;
	d2 += [](int x, int y){return x + y;};
	d2 += [](int x, int y){return x * y;};
	for (auto ret : d2(3, 5))
	{
		cout << ret << endl;
	}

    // delegate with normal functions without return value
    delegate<void, int, int> d3;
	d3 += func1;
	d3 += func2;
	d3(3, 5);

    // delegate with class member functions without return value
    A a = A();
    using delegateFunc = std::function<void(int, int)>;
    delegateFunc delegateFunc1 = std::bind(&A::func1, a, std::placeholders::_1, std::placeholders::_2);
    delegateFunc delegateFunc2 = std::bind(&A::func2, a, std::placeholders::_1, std::placeholders::_2);

    delegate<void, int, int> d4;

	d4 += delegateFunc1;
	d4 += delegateFunc2;
	d4(3, 5);

	return 0;
}