Skip to content

Instantly share code, notes, and snippets.

@ttsuki
Last active January 26, 2021 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ttsuki/cf4aeb5772715b98c39d30d136f36980 to your computer and use it in GitHub Desktop.
Save ttsuki/cf4aeb5772715b98c39d30d136f36980 to your computer and use it in GitHub Desktop.
WrapMemFuncAsRawFunctionPointer
#include "WrapMemFuncAsRawFunctionPointer.hpp"
class Interface
{
public:
virtual ~Interface() = default;
virtual int A() =0;
virtual int B(const int&) = 0;
virtual int& C(int&&, float) = 0;
};
class InterfaceImpl : public Interface
{
public:
int x{12};
int A() override { return 10; }
int B(const int&) override { return 11; }
int& C(int&&, float) override { return x; }
};
int main()
{
InterfaceImpl a{};
// FuncA is `int &(__stdcall *)(Interface *, int&&, float)`
auto FuncA = WrapMemberFunctionAsRawFunctionPointer<&Interface::C>();
FuncA(&a, 1, 1.2f) = 15;
int result = FuncA(&a, 1, 1.2f);
return result; // 15
}
#include <utility>
namespace detail
{
enum struct CallConv
{
Cdecl,
StdCall,
};
template <class TResult, CallConv X, class...TArgs>
struct FunctionPointerWithCallingConvention;
template <class TResult, class...TArgs>
struct FunctionPointerWithCallingConvention<TResult, CallConv::Cdecl, TArgs...>
{
using Type = TResult (__cdecl*)(TArgs ...);
};
template <class TResult, class...TArgs>
struct FunctionPointerWithCallingConvention<TResult, CallConv::StdCall, TArgs...>
{
using Type = TResult (__stdcall*)(TArgs ...);
};
template <class TFunc>
struct ProxyFunction;
template <class TResult, class TInterface, class...TArgs>
struct ProxyFunction<TResult (TInterface::*)(TArgs ...)>
{
template <TResult (TInterface::* TMemFunc)(TArgs ...), CallConv TCallConv>
static auto GetWrapped()
-> typename FunctionPointerWithCallingConvention<TResult, TCallConv, TInterface*, TArgs...>::Type
{
return [](TInterface* instance, TArgs ...args) -> decltype(auto)
{
return (instance->*TMemFunc)(std::forward<TArgs>(args)...);
};
}
};
template <auto TMemFunc, CallConv TCallConv = CallConv::StdCall>
constexpr auto WrapMemberFunctionAsRawFunctionPointer()
{
return detail::ProxyFunction<decltype(TMemFunc)>::template GetWrapped<TMemFunc, TCallConv>();
}
}
using detail::CallConv;
using detail::WrapMemberFunctionAsRawFunctionPointer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment