#include <iostream>
#include <functional>
 
#include <tuple>
#include <iostream>
using std::cout;
using std::endl;
using namespace std::placeholders;
 
// helpers for tuple unrolling
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
 
// simple function
double foo_fn(int x, float y, double z)
{
  return x + y + z;
}
 
// structure with memner function to call
struct foo_struct
{
	// member function to be used as a delegate
	double foo_fn(int x, float y, double z)
	{
		return x + y + z;
	}
	// this member function has different signature - but it can be used too
	// please not that argument order is changed too
	double foo_fn_4(int x, double z, float y, long xx)
	{
		return x + y + z + xx;
	}
};
 
// delegate class that holds as delegate as its params for future call
template <typename Ret, typename ...Args>
struct delayed_call
{
  // tuple can be used as FunctionParamsPack type
  typedef std::tuple<Args...> params_type;
  // std::function as delegate type
  typedef std::function<Ret(Args...)> function_type;
 
  // stored parameters
  params_type params;
  // stored delegate
  function_type func;
 
  // invocation
  Ret operator()()
  {
    return callFunc(typename gens<sizeof...(Args)>::type());
  }
  // direct invocation
  Ret operator()(Args... args)
  {
    return func(args...);
  }
 
  // internal invocation with tuple unrolling
  template<int ...S>
  double callFunc(seq<S...>)
  {
    return func(std::get<S>(params) ...);
  }
};
 
int main(void)
{
  // arguments
  std::tuple<int, float, double> t = std::make_tuple(1, 5, 10);
  // var #1 - you can use simple function as delegate
  delayed_call<double, int,float, double> saved_foo_fn{t, foo_fn};
  foo_struct fs;
  // var #2 - you can use member function as delegate
  delayed_call<double, int,float, double> saved_foo_fn_struct{t, std::bind(&foo_struct::foo_fn, fs, _1, _2, _3)};
  // var #3 - you can use member function with different signature as delegate. bind 0 to xx
  // please not that argument order is changed
  delayed_call<double, int,float, double> saved_foo_fn_struct_4{t, std::bind(&foo_struct::foo_fn_4, fs, _1, _3, _2, 0l)};
  // var #4 - you can use lambda function as delegate
  delayed_call<double, int,float, double> saved_lambda{t, [](int x, float y, double z)
	{
		return x + y + z;
	}
  };
  cout << "saved_foo_fn: " << saved_foo_fn() << endl;
  cout << "saved_foo_fn_struct: " << saved_foo_fn_struct() << endl;
  cout << "saved_foo_fn_struct_4: " << saved_foo_fn_struct_4() << endl;
  cout << "saved_lambda: " << saved_lambda() << endl;
  cout << "direct call with (1,2,3) to a member: " << saved_foo_fn_struct(1, 2, 3) << endl;
}
				I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8ZnVuY3Rpb25hbD4KCiNpbmNsdWRlIDx0dXBsZT4KI2luY2x1ZGUgPGlvc3RyZWFtPgp1c2luZyBzdGQ6OmNvdXQ7CnVzaW5nIHN0ZDo6ZW5kbDsKdXNpbmcgbmFtZXNwYWNlIHN0ZDo6cGxhY2Vob2xkZXJzOwoKLy8gaGVscGVycyBmb3IgdHVwbGUgdW5yb2xsaW5nCnRlbXBsYXRlPGludCAuLi4+IHN0cnVjdCBzZXEge307CnRlbXBsYXRlPGludCBOLCBpbnQgLi4uUz4gc3RydWN0IGdlbnMgOiBnZW5zPE4tMSwgTi0xLCBTLi4uPiB7fTsKdGVtcGxhdGU8aW50IC4uLlM+IHN0cnVjdCBnZW5zPDAsIFMuLi4+eyB0eXBlZGVmIHNlcTxTLi4uPiB0eXBlOyB9OwoKLy8gc2ltcGxlIGZ1bmN0aW9uCmRvdWJsZSBmb29fZm4oaW50IHgsIGZsb2F0IHksIGRvdWJsZSB6KQp7CiAgcmV0dXJuIHggKyB5ICsgejsKfQoKLy8gc3RydWN0dXJlIHdpdGggbWVtbmVyIGZ1bmN0aW9uIHRvIGNhbGwKc3RydWN0IGZvb19zdHJ1Y3QKewoJLy8gbWVtYmVyIGZ1bmN0aW9uIHRvIGJlIHVzZWQgYXMgYSBkZWxlZ2F0ZQoJZG91YmxlIGZvb19mbihpbnQgeCwgZmxvYXQgeSwgZG91YmxlIHopCgl7CgkJcmV0dXJuIHggKyB5ICsgejsKCX0KCS8vIHRoaXMgbWVtYmVyIGZ1bmN0aW9uIGhhcyBkaWZmZXJlbnQgc2lnbmF0dXJlIC0gYnV0IGl0IGNhbiBiZSB1c2VkIHRvbwoJLy8gcGxlYXNlIG5vdCB0aGF0IGFyZ3VtZW50IG9yZGVyIGlzIGNoYW5nZWQgdG9vCglkb3VibGUgZm9vX2ZuXzQoaW50IHgsIGRvdWJsZSB6LCBmbG9hdCB5LCBsb25nIHh4KQoJewoJCXJldHVybiB4ICsgeSArIHogKyB4eDsKCX0KfTsKCi8vIGRlbGVnYXRlIGNsYXNzIHRoYXQgaG9sZHMgYXMgZGVsZWdhdGUgYXMgaXRzIHBhcmFtcyBmb3IgZnV0dXJlIGNhbGwKdGVtcGxhdGUgPHR5cGVuYW1lIFJldCwgdHlwZW5hbWUgLi4uQXJncz4Kc3RydWN0IGRlbGF5ZWRfY2FsbAp7CiAgLy8gdHVwbGUgY2FuIGJlIHVzZWQgYXMgRnVuY3Rpb25QYXJhbXNQYWNrIHR5cGUKICB0eXBlZGVmIHN0ZDo6dHVwbGU8QXJncy4uLj4gcGFyYW1zX3R5cGU7CiAgLy8gc3RkOjpmdW5jdGlvbiBhcyBkZWxlZ2F0ZSB0eXBlCiAgdHlwZWRlZiBzdGQ6OmZ1bmN0aW9uPFJldChBcmdzLi4uKT4gZnVuY3Rpb25fdHlwZTsKICAKICAvLyBzdG9yZWQgcGFyYW1ldGVycwogIHBhcmFtc190eXBlIHBhcmFtczsKICAvLyBzdG9yZWQgZGVsZWdhdGUKICBmdW5jdGlvbl90eXBlIGZ1bmM7CgogIC8vIGludm9jYXRpb24KICBSZXQgb3BlcmF0b3IoKSgpCiAgewogICAgcmV0dXJuIGNhbGxGdW5jKHR5cGVuYW1lIGdlbnM8c2l6ZW9mLi4uKEFyZ3MpPjo6dHlwZSgpKTsKICB9CiAgLy8gZGlyZWN0IGludm9jYXRpb24KICBSZXQgb3BlcmF0b3IoKShBcmdzLi4uIGFyZ3MpCiAgewogICAgcmV0dXJuIGZ1bmMoYXJncy4uLik7CiAgfQoKICAvLyBpbnRlcm5hbCBpbnZvY2F0aW9uIHdpdGggdHVwbGUgdW5yb2xsaW5nCiAgdGVtcGxhdGU8aW50IC4uLlM+CiAgZG91YmxlIGNhbGxGdW5jKHNlcTxTLi4uPikKICB7CiAgICByZXR1cm4gZnVuYyhzdGQ6OmdldDxTPihwYXJhbXMpIC4uLik7CiAgfQp9OwoKaW50IG1haW4odm9pZCkKewogIC8vIGFyZ3VtZW50cwogIHN0ZDo6dHVwbGU8aW50LCBmbG9hdCwgZG91YmxlPiB0ID0gc3RkOjptYWtlX3R1cGxlKDEsIDUsIDEwKTsKICAvLyB2YXIgIzEgLSB5b3UgY2FuIHVzZSBzaW1wbGUgZnVuY3Rpb24gYXMgZGVsZWdhdGUKICBkZWxheWVkX2NhbGw8ZG91YmxlLCBpbnQsZmxvYXQsIGRvdWJsZT4gc2F2ZWRfZm9vX2Zue3QsIGZvb19mbn07CiAgZm9vX3N0cnVjdCBmczsKICAvLyB2YXIgIzIgLSB5b3UgY2FuIHVzZSBtZW1iZXIgZnVuY3Rpb24gYXMgZGVsZWdhdGUKICBkZWxheWVkX2NhbGw8ZG91YmxlLCBpbnQsZmxvYXQsIGRvdWJsZT4gc2F2ZWRfZm9vX2ZuX3N0cnVjdHt0LCBzdGQ6OmJpbmQoJmZvb19zdHJ1Y3Q6OmZvb19mbiwgZnMsIF8xLCBfMiwgXzMpfTsKICAvLyB2YXIgIzMgLSB5b3UgY2FuIHVzZSBtZW1iZXIgZnVuY3Rpb24gd2l0aCBkaWZmZXJlbnQgc2lnbmF0dXJlIGFzIGRlbGVnYXRlLiBiaW5kIDAgdG8geHgKICAvLyBwbGVhc2Ugbm90IHRoYXQgYXJndW1lbnQgb3JkZXIgaXMgY2hhbmdlZAogIGRlbGF5ZWRfY2FsbDxkb3VibGUsIGludCxmbG9hdCwgZG91YmxlPiBzYXZlZF9mb29fZm5fc3RydWN0XzR7dCwgc3RkOjpiaW5kKCZmb29fc3RydWN0Ojpmb29fZm5fNCwgZnMsIF8xLCBfMywgXzIsIDBsKX07CiAgLy8gdmFyICM0IC0geW91IGNhbiB1c2UgbGFtYmRhIGZ1bmN0aW9uIGFzIGRlbGVnYXRlCiAgZGVsYXllZF9jYWxsPGRvdWJsZSwgaW50LGZsb2F0LCBkb3VibGU+IHNhdmVkX2xhbWJkYXt0LCBbXShpbnQgeCwgZmxvYXQgeSwgZG91YmxlIHopCgl7CgkJcmV0dXJuIHggKyB5ICsgejsKCX0KICB9OwogIGNvdXQgPDwgInNhdmVkX2Zvb19mbjogIiA8PCBzYXZlZF9mb29fZm4oKSA8PCBlbmRsOwogIGNvdXQgPDwgInNhdmVkX2Zvb19mbl9zdHJ1Y3Q6ICIgPDwgc2F2ZWRfZm9vX2ZuX3N0cnVjdCgpIDw8IGVuZGw7CiAgY291dCA8PCAic2F2ZWRfZm9vX2ZuX3N0cnVjdF80OiAiIDw8IHNhdmVkX2Zvb19mbl9zdHJ1Y3RfNCgpIDw8IGVuZGw7CiAgY291dCA8PCAic2F2ZWRfbGFtYmRhOiAiIDw8IHNhdmVkX2xhbWJkYSgpIDw8IGVuZGw7CiAgY291dCA8PCAiZGlyZWN0IGNhbGwgd2l0aCAoMSwyLDMpIHRvIGEgbWVtYmVyOiAiIDw8IHNhdmVkX2Zvb19mbl9zdHJ1Y3QoMSwgMiwgMykgPDwgZW5kbDsKfQ==