#include <memory>
#include <iostream>
#include <functional>
template<class... Args>
class DelegateTemplate;
class Delegate
{
std::unique_ptr<Delegate> mPtr;
public:
virtual ~Delegate() { }
template<class R, class T, class... Args>
void RegisterFunction(R(*target)(Args...), T(*callback)(R), Args... args)
{
mPtr.reset(new DelegateTemplate<R(Args...), T(R)>(target, callback, args...));
}
template<class R, class S, class T, class... Args>
void RegisterFunction(R(S::*target)(Args...), S* obj, T(*callback)(R), Args... args)
{
mPtr.reset(new DelegateTemplate<R(Args...), T(R)>(target, obj, callback, args...));
}
virtual void CallFunction()
{
mPtr->CallFunction();
}
};
template<class R, class T, class... Args>
class DelegateTemplate<R(Args...), T(R)> : public Delegate
{
std::function<R()> mTarget;
std::function<T(R)> mCallback;
public:
DelegateTemplate(R(*target)(Args...), T(*callback)(R), Args... args)
: mTarget(std::bind(target, args...))
, mCallback(callback)
{
}
template<class S>
DelegateTemplate(R(S::*target)(Args...), S* obj, T(*callback)(R), Args... args)
: mTarget(std::bind(target, obj, args...))
, mCallback(callback)
{
}
~DelegateTemplate() { }
void CallFunction() override
{
mCallback(mTarget());
}
};
int Foo1(int i)
{
std::cout << "Foo1.i = " << i << std::endl;
return i;
}
void Callback1(int i)
{
std::cout << "Callback1.i = " << i << std::endl;
}
const char* Foo2(double r)
{
std::cout << "Foo2.r = " << r << std::endl;
return "hello world";
}
void Callback2(const char* str)
{
std::cout << "Callback1.str = " << str << std::endl;
}
class Test
{
public:
int Foo3(const char* str)
{
std::cout << "Test::Foo3.str = " << str << std::endl;
return 4;
}
};
int RefFoo(int &value) {
std::cout << "RefFoo.value = " << value << std::endl;
++value;
return value;
}
int main()
{
int source_value_for_direct_call = 5;
std::cout << "source_value_for_direct_call before direct call = " <<
source_value_for_direct_call << std::endl;
RefFoo(source_value_for_direct_call);
std::cout << "source_value_for_direct_call after direct call = " <<
source_value_for_direct_call << std::endl;
int source_value_for_delegate_call = 5;
Delegate d;
d.RegisterFunction(&RefFoo,&Callback1, source_value_for_delegate_call);
std::cout << "source_value_for_delegate_call before delegate call = " <<
source_value_for_delegate_call << std::endl;
d.CallFunction();
std::cout << "source_value_for_delegate_call after delegate call = " <<
source_value_for_delegate_call << std::endl;
}
I2luY2x1ZGUgPG1lbW9yeT4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8ZnVuY3Rpb25hbD4KCnRlbXBsYXRlPGNsYXNzLi4uIEFyZ3M+CmNsYXNzIERlbGVnYXRlVGVtcGxhdGU7CgpjbGFzcyBEZWxlZ2F0ZQp7CiAgICBzdGQ6OnVuaXF1ZV9wdHI8RGVsZWdhdGU+IG1QdHI7CnB1YmxpYzoKICAgIHZpcnR1YWwgfkRlbGVnYXRlKCkgeyB9CgogICAgdGVtcGxhdGU8Y2xhc3MgUiwgY2xhc3MgVCwgY2xhc3MuLi4gQXJncz4KICAgIHZvaWQgUmVnaXN0ZXJGdW5jdGlvbihSKCp0YXJnZXQpKEFyZ3MuLi4pLCBUKCpjYWxsYmFjaykoUiksIEFyZ3MuLi4gYXJncykKICAgIHsKICAgICAgICBtUHRyLnJlc2V0KG5ldyBEZWxlZ2F0ZVRlbXBsYXRlPFIoQXJncy4uLiksIFQoUik+KHRhcmdldCwgY2FsbGJhY2ssIGFyZ3MuLi4pKTsKICAgIH0KCiAgICB0ZW1wbGF0ZTxjbGFzcyBSLCBjbGFzcyBTLCBjbGFzcyBULCBjbGFzcy4uLiBBcmdzPgogICAgdm9pZCBSZWdpc3RlckZ1bmN0aW9uKFIoUzo6KnRhcmdldCkoQXJncy4uLiksIFMqIG9iaiwgVCgqY2FsbGJhY2spKFIpLCBBcmdzLi4uIGFyZ3MpCiAgICB7CiAgICAgICAgbVB0ci5yZXNldChuZXcgRGVsZWdhdGVUZW1wbGF0ZTxSKEFyZ3MuLi4pLCBUKFIpPih0YXJnZXQsIG9iaiwgY2FsbGJhY2ssIGFyZ3MuLi4pKTsKICAgIH0KCiAgICB2aXJ0dWFsIHZvaWQgQ2FsbEZ1bmN0aW9uKCkKICAgIHsKICAgICAgICBtUHRyLT5DYWxsRnVuY3Rpb24oKTsKICAgIH0KfTsKCnRlbXBsYXRlPGNsYXNzIFIsIGNsYXNzIFQsIGNsYXNzLi4uIEFyZ3M+CmNsYXNzIERlbGVnYXRlVGVtcGxhdGU8UihBcmdzLi4uKSwgVChSKT4gOiBwdWJsaWMgRGVsZWdhdGUKewogICAgc3RkOjpmdW5jdGlvbjxSKCk+IG1UYXJnZXQ7CiAgICBzdGQ6OmZ1bmN0aW9uPFQoUik+IG1DYWxsYmFjazsKcHVibGljOgogICAgRGVsZWdhdGVUZW1wbGF0ZShSKCp0YXJnZXQpKEFyZ3MuLi4pLCBUKCpjYWxsYmFjaykoUiksIEFyZ3MuLi4gYXJncykKICAgIDogbVRhcmdldChzdGQ6OmJpbmQodGFyZ2V0LCBhcmdzLi4uKSkKICAgICwgbUNhbGxiYWNrKGNhbGxiYWNrKQogICAgewogICAgfQoKICAgIHRlbXBsYXRlPGNsYXNzIFM+CiAgICBEZWxlZ2F0ZVRlbXBsYXRlKFIoUzo6KnRhcmdldCkoQXJncy4uLiksIFMqIG9iaiwgVCgqY2FsbGJhY2spKFIpLCBBcmdzLi4uIGFyZ3MpCiAgICA6IG1UYXJnZXQoc3RkOjpiaW5kKHRhcmdldCwgb2JqLCBhcmdzLi4uKSkKICAgICwgbUNhbGxiYWNrKGNhbGxiYWNrKQogICAgewogICAgfQoKICAgIH5EZWxlZ2F0ZVRlbXBsYXRlKCkgeyB9CgogICAgdm9pZCBDYWxsRnVuY3Rpb24oKSBvdmVycmlkZQogICAgewogICAgICAgIG1DYWxsYmFjayhtVGFyZ2V0KCkpOwogICAgfQp9OwoKaW50IEZvbzEoaW50IGkpCnsKICAgIHN0ZDo6Y291dCA8PCAiRm9vMS5pID0gIiA8PCBpIDw8IHN0ZDo6ZW5kbDsKICAgIHJldHVybiBpOwp9Cgp2b2lkIENhbGxiYWNrMShpbnQgaSkKewogICAgc3RkOjpjb3V0IDw8ICJDYWxsYmFjazEuaSA9ICIgPDwgaSA8PCBzdGQ6OmVuZGw7Cn0KCmNvbnN0IGNoYXIqIEZvbzIoZG91YmxlIHIpCnsKICAgIHN0ZDo6Y291dCA8PCAiRm9vMi5yID0gIiA8PCByIDw8IHN0ZDo6ZW5kbDsKICAgIHJldHVybiAiaGVsbG8gd29ybGQiOwp9Cgp2b2lkIENhbGxiYWNrMihjb25zdCBjaGFyKiBzdHIpCnsKICAgIHN0ZDo6Y291dCA8PCAiQ2FsbGJhY2sxLnN0ciA9ICIgPDwgc3RyIDw8IHN0ZDo6ZW5kbDsKfQoKY2xhc3MgVGVzdAp7CnB1YmxpYzoKICAgIGludCBGb28zKGNvbnN0IGNoYXIqIHN0cikKICAgIHsKICAgICAgICBzdGQ6OmNvdXQgPDwgIlRlc3Q6OkZvbzMuc3RyID0gIiA8PCBzdHIgPDwgc3RkOjplbmRsOwogICAgICAgIHJldHVybiA0OwogICAgfQp9OwoKCmludCBSZWZGb28oaW50ICZ2YWx1ZSkgewoJc3RkOjpjb3V0IDw8ICJSZWZGb28udmFsdWUgPSAiIDw8IHZhbHVlIDw8IHN0ZDo6ZW5kbDsKCSsrdmFsdWU7CglyZXR1cm4gdmFsdWU7Cn0KCgppbnQgbWFpbigpCnsKCWludCBzb3VyY2VfdmFsdWVfZm9yX2RpcmVjdF9jYWxsID0gNTsKCXN0ZDo6Y291dCA8PCAic291cmNlX3ZhbHVlX2Zvcl9kaXJlY3RfY2FsbCBiZWZvcmUgZGlyZWN0IGNhbGwgPSAiIDw8IAoJc291cmNlX3ZhbHVlX2Zvcl9kaXJlY3RfY2FsbCA8PCBzdGQ6OmVuZGw7CglSZWZGb28oc291cmNlX3ZhbHVlX2Zvcl9kaXJlY3RfY2FsbCk7CglzdGQ6OmNvdXQgPDwgInNvdXJjZV92YWx1ZV9mb3JfZGlyZWN0X2NhbGwgYWZ0ZXIgZGlyZWN0IGNhbGwgPSAiIDw8IAoJc291cmNlX3ZhbHVlX2Zvcl9kaXJlY3RfY2FsbCA8PCBzdGQ6OmVuZGw7CgkKCWludCBzb3VyY2VfdmFsdWVfZm9yX2RlbGVnYXRlX2NhbGwgPSA1OyAKCURlbGVnYXRlIGQ7CglkLlJlZ2lzdGVyRnVuY3Rpb24oJlJlZkZvbywmQ2FsbGJhY2sxLCBzb3VyY2VfdmFsdWVfZm9yX2RlbGVnYXRlX2NhbGwpOwoJCiAgICBzdGQ6OmNvdXQgPDwgInNvdXJjZV92YWx1ZV9mb3JfZGVsZWdhdGVfY2FsbCBiZWZvcmUgZGVsZWdhdGUgY2FsbCA9ICIgPDwKICAgIHNvdXJjZV92YWx1ZV9mb3JfZGVsZWdhdGVfY2FsbCA8PCBzdGQ6OmVuZGw7CiAgICBkLkNhbGxGdW5jdGlvbigpOwogICAgc3RkOjpjb3V0IDw8ICJzb3VyY2VfdmFsdWVfZm9yX2RlbGVnYXRlX2NhbGwgYWZ0ZXIgZGVsZWdhdGUgY2FsbCA9ICIgPDwKICAgIHNvdXJjZV92YWx1ZV9mb3JfZGVsZWdhdGVfY2FsbCA8PCBzdGQ6OmVuZGw7Cn0K
prog.cpp: In function ‘int main()’:
prog.cpp:110:71: error: no matching function for call to ‘Delegate::RegisterFunction(int (*)(int&), void (*)(int), int&)’
d.RegisterFunction(&RefFoo,&Callback1, source_value_for_delegate_call);
^
prog.cpp:110:71: note: candidates are:
prog.cpp:15:10: note: template<class R, class T, class ... Args> void Delegate::RegisterFunction(R (*)(Args ...), T (*)(R), Args ...)
void RegisterFunction(R(*target)(Args...), T(*callback)(R), Args... args)
^
prog.cpp:15:10: note: template argument deduction/substitution failed:
prog.cpp:110:71: note: inconsistent parameter pack deduction with ‘int&’ and ‘int’
d.RegisterFunction(&RefFoo,&Callback1, source_value_for_delegate_call);
^
prog.cpp:21:10: note: template<class R, class S, class T, class ... Args> void Delegate::RegisterFunction(R (S::*)(Args ...), S*, T (*)(R), Args ...)
void RegisterFunction(R(S::*target)(Args...), S* obj, T(*callback)(R), Args... args)
^
prog.cpp:21:10: note: template argument deduction/substitution failed:
prog.cpp:110:71: note: mismatched types ‘R (S::*)(Args ...)’ and ‘int (*)(int&)’
d.RegisterFunction(&RefFoo,&Callback1, source_value_for_delegate_call);
^