#include <iostream>
#include <cstring>
template<typename ReturnType, typename... ParameterTypes>
class IDelegateBinding
{
public:
virtual ReturnType Execute(void* Object, ParameterTypes... Parameters) = 0;
};
template<typename ObjectType, typename ReturnType, typename... ParameterTypes>
class FDelegateBinding : public IDelegateBinding<ReturnType, ParameterTypes...>
{
using MethodType = ReturnType (ObjectType::*)(ParameterTypes...);
MethodType BoundMethod;
public:
FDelegateBinding(MethodType Method)
: BoundMethod(Method)
{
}
virtual ReturnType Execute(void* Object, ParameterTypes... Parameters) override
{
return (((ObjectType*)Object)->*BoundMethod)(Parameters...);
}
};
template<typename ReturnType, typename... ParameterTypes>
class FDelegate
{
using DummyDelegateBinding = FDelegateBinding<class FDummyClass, ReturnType, ParameterTypes...>;
typename std::aligned_storage<sizeof(DummyDelegateBinding), alignof(DummyDelegateBinding)>::type Binding;
public:
FDelegate()
{
std::memset(&Binding, 0, sizeof(Binding));
}
template<typename ClassName>
void Bind(ReturnType (ClassName::*Method)(ParameterTypes...))
{
new (&Binding) FDelegateBinding<ClassName, ReturnType, ParameterTypes...>(Method);
}
void Unbind()
{
std::memset(Binding, 0, sizeof(Binding));
}
bool IsBound() const
{
return (void*&)Binding != nullptr;
}
template<typename ObjectType>
ReturnType Execute(ObjectType* Object, ParameterTypes... Parameters)
{
return ((IDelegateBinding<ReturnType, ParameterTypes...>&)Binding).Execute(Object, Parameters...);
}
template<typename ObjectType>
ReturnType ExecuteIfBound(ObjectType* Object, ParameterTypes... Parameters)
{
if (IsBound())
{
return Execute<ObjectType>(Object, Parameters...);
}
}
};
class FSampleBase
{
protected:
FDelegate<void, int> NotifyFooInvoked;
public:
void Foo(int Value)
{
NotifyFooInvoked.ExecuteIfBound(this, Value);
}
};
class FSampleDerived : public FSampleBase
{
int SampleData;
public:
FSampleDerived(int Data)
: SampleData(Data)
{
NotifyFooInvoked.Bind(&FSampleDerived::OnFooInvoked);
}
void OnFooInvoked(int Value)
{
std::cout << "Foo Invoked: " << Value << " [Sample Data: " << SampleData << "]" << std::endl;
}
};
int main()
{
FSampleDerived FirstSample(11);
FSampleDerived* SecondSample = (FSampleDerived*)std::malloc(sizeof(FSampleDerived));
std::memcpy(SecondSample, &FirstSample, sizeof(FSampleDerived));
FirstSample.Foo(1);
SecondSample->Foo(2);
std::free(SecondSample);
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y3N0cmluZz4KCnRlbXBsYXRlPHR5cGVuYW1lIFJldHVyblR5cGUsIHR5cGVuYW1lLi4uIFBhcmFtZXRlclR5cGVzPgpjbGFzcyBJRGVsZWdhdGVCaW5kaW5nCnsKcHVibGljOgoKCXZpcnR1YWwgUmV0dXJuVHlwZSBFeGVjdXRlKHZvaWQqIE9iamVjdCwgUGFyYW1ldGVyVHlwZXMuLi4gUGFyYW1ldGVycykgPSAwOwp9OwoKdGVtcGxhdGU8dHlwZW5hbWUgT2JqZWN0VHlwZSwgdHlwZW5hbWUgUmV0dXJuVHlwZSwgdHlwZW5hbWUuLi4gUGFyYW1ldGVyVHlwZXM+CmNsYXNzIEZEZWxlZ2F0ZUJpbmRpbmcgOiBwdWJsaWMgSURlbGVnYXRlQmluZGluZzxSZXR1cm5UeXBlLCBQYXJhbWV0ZXJUeXBlcy4uLj4KewoJdXNpbmcgTWV0aG9kVHlwZSA9IFJldHVyblR5cGUgKE9iamVjdFR5cGU6OiopKFBhcmFtZXRlclR5cGVzLi4uKTsKCQoJTWV0aG9kVHlwZSBCb3VuZE1ldGhvZDsKCQpwdWJsaWM6CgkKCUZEZWxlZ2F0ZUJpbmRpbmcoTWV0aG9kVHlwZSBNZXRob2QpCgkJOiBCb3VuZE1ldGhvZChNZXRob2QpCgl7Cgl9CgkKCXZpcnR1YWwgUmV0dXJuVHlwZSBFeGVjdXRlKHZvaWQqIE9iamVjdCwgUGFyYW1ldGVyVHlwZXMuLi4gUGFyYW1ldGVycykgb3ZlcnJpZGUKCXsKCQlyZXR1cm4gKCgoT2JqZWN0VHlwZSopT2JqZWN0KS0+KkJvdW5kTWV0aG9kKShQYXJhbWV0ZXJzLi4uKTsKCX0KfTsKCnRlbXBsYXRlPHR5cGVuYW1lIFJldHVyblR5cGUsIHR5cGVuYW1lLi4uIFBhcmFtZXRlclR5cGVzPgpjbGFzcyBGRGVsZWdhdGUKewoJdXNpbmcgRHVtbXlEZWxlZ2F0ZUJpbmRpbmcgPSBGRGVsZWdhdGVCaW5kaW5nPGNsYXNzIEZEdW1teUNsYXNzLCBSZXR1cm5UeXBlLCBQYXJhbWV0ZXJUeXBlcy4uLj47CgkKCXR5cGVuYW1lIHN0ZDo6YWxpZ25lZF9zdG9yYWdlPHNpemVvZihEdW1teURlbGVnYXRlQmluZGluZyksIGFsaWdub2YoRHVtbXlEZWxlZ2F0ZUJpbmRpbmcpPjo6dHlwZSBCaW5kaW5nOwoJCnB1YmxpYzoKCglGRGVsZWdhdGUoKQoJewoJCXN0ZDo6bWVtc2V0KCZCaW5kaW5nLCAwLCBzaXplb2YoQmluZGluZykpOwoJfQoJCgl0ZW1wbGF0ZTx0eXBlbmFtZSBDbGFzc05hbWU+Cgl2b2lkIEJpbmQoUmV0dXJuVHlwZSAoQ2xhc3NOYW1lOjoqTWV0aG9kKShQYXJhbWV0ZXJUeXBlcy4uLikpCgl7CgkJbmV3ICgmQmluZGluZykgRkRlbGVnYXRlQmluZGluZzxDbGFzc05hbWUsIFJldHVyblR5cGUsIFBhcmFtZXRlclR5cGVzLi4uPihNZXRob2QpOwoJfQoJCgl2b2lkIFVuYmluZCgpCgl7CgkJc3RkOjptZW1zZXQoQmluZGluZywgMCwgc2l6ZW9mKEJpbmRpbmcpKTsKCX0KCQoJYm9vbCBJc0JvdW5kKCkgY29uc3QKCXsKCQlyZXR1cm4gKHZvaWQqJilCaW5kaW5nICE9IG51bGxwdHI7Cgl9CgkKCXRlbXBsYXRlPHR5cGVuYW1lIE9iamVjdFR5cGU+CglSZXR1cm5UeXBlIEV4ZWN1dGUoT2JqZWN0VHlwZSogT2JqZWN0LCBQYXJhbWV0ZXJUeXBlcy4uLiBQYXJhbWV0ZXJzKQoJewoJCXJldHVybiAoKElEZWxlZ2F0ZUJpbmRpbmc8UmV0dXJuVHlwZSwgUGFyYW1ldGVyVHlwZXMuLi4+JilCaW5kaW5nKS5FeGVjdXRlKE9iamVjdCwgUGFyYW1ldGVycy4uLik7Cgl9CgkKCXRlbXBsYXRlPHR5cGVuYW1lIE9iamVjdFR5cGU+CglSZXR1cm5UeXBlIEV4ZWN1dGVJZkJvdW5kKE9iamVjdFR5cGUqIE9iamVjdCwgUGFyYW1ldGVyVHlwZXMuLi4gUGFyYW1ldGVycykKCXsKCQlpZiAoSXNCb3VuZCgpKQoJCXsKCQkJcmV0dXJuIEV4ZWN1dGU8T2JqZWN0VHlwZT4oT2JqZWN0LCBQYXJhbWV0ZXJzLi4uKTsKCQl9Cgl9Cn07CgpjbGFzcyBGU2FtcGxlQmFzZQp7CnByb3RlY3RlZDoKIAoJRkRlbGVnYXRlPHZvaWQsIGludD4gTm90aWZ5Rm9vSW52b2tlZDsKIApwdWJsaWM6CiAKCXZvaWQgRm9vKGludCBWYWx1ZSkKCXsKCQlOb3RpZnlGb29JbnZva2VkLkV4ZWN1dGVJZkJvdW5kKHRoaXMsIFZhbHVlKTsKCX0KfTsKIApjbGFzcyBGU2FtcGxlRGVyaXZlZCA6IHB1YmxpYyBGU2FtcGxlQmFzZQp7CglpbnQgU2FtcGxlRGF0YTsKIApwdWJsaWM6CiAKCUZTYW1wbGVEZXJpdmVkKGludCBEYXRhKQoJCTogU2FtcGxlRGF0YShEYXRhKQoJewoJCU5vdGlmeUZvb0ludm9rZWQuQmluZCgmRlNhbXBsZURlcml2ZWQ6Ok9uRm9vSW52b2tlZCk7Cgl9CiAKCXZvaWQgT25Gb29JbnZva2VkKGludCBWYWx1ZSkKCXsKCQlzdGQ6OmNvdXQgPDwgIkZvbyBJbnZva2VkOiAiIDw8IFZhbHVlIDw8ICIgW1NhbXBsZSBEYXRhOiAiIDw8IFNhbXBsZURhdGEgPDwgIl0iIDw8IHN0ZDo6ZW5kbDsKCX0KfTsKIAppbnQgbWFpbigpCnsKCUZTYW1wbGVEZXJpdmVkIEZpcnN0U2FtcGxlKDExKTsKCUZTYW1wbGVEZXJpdmVkKiBTZWNvbmRTYW1wbGUgPSAoRlNhbXBsZURlcml2ZWQqKXN0ZDo6bWFsbG9jKHNpemVvZihGU2FtcGxlRGVyaXZlZCkpOwogCglzdGQ6Om1lbWNweShTZWNvbmRTYW1wbGUsICZGaXJzdFNhbXBsZSwgc2l6ZW9mKEZTYW1wbGVEZXJpdmVkKSk7CiAKCUZpcnN0U2FtcGxlLkZvbygxKTsKCVNlY29uZFNhbXBsZS0+Rm9vKDIpOwogCglzdGQ6OmZyZWUoU2Vjb25kU2FtcGxlKTsKIAoJcmV0dXJuIDA7Cn0=