std::function<void()> function = [instance]( ) { instance->desired_function( [...] ); };
struct tag_stdcall { };
struct tag_thiscall { };
struct tag_cdecl { };
namespace details {
template<typename _Tag, typename _Base>
class _Function_wrapper_base
{
public:
using tag_type = _Tag;
using self_type = _Base;
using base_type = _Function_wrapper_base<_Tag, _Base>;
protected:
_Function_wrapper_base( )
: f_( nullptr )
{}
_Function_wrapper_base( void *f )
: f_( f )
{}
template<typename R, typename..._Args>
_Function_wrapper_base( R(*f)( _Args... ) )
: f_( reinterpret_cast<void*>( f ) )
{}
_Function_wrapper_base( std::nullptr_t )
: f_( nullptr )
{}
void *__Target( )
{
return f_;
}
void __Target( void *f )
{
f_ = f;
}
template<typename R, typename..._Args>
void __Target( R(*f)( _Args... ) )
{
f_ = reinterpret_cast<void*>( f );
}
void __Target( std::nullptr_t )
{
f_ = nullptr;
}
bool __Empty( )
{
return f_ == nullptr;
}
private:
void *f_;
};
template<typename _Tag>
struct is_tag : public std::false_type {};
template<>
struct is_tag<tag_stdcall> : public std::true_type {};
template<>
struct is_tag<tag_thiscall> : public std::true_type {};
template<>
struct is_tag<tag_cdecl> : public std::true_type {};
}
template<typename _Tag>
class function_wrapper
{
// if _Tag is not tag_stdcall/thiscall/cdecl this will cause a compiler error
static_assert( details::is_tag<_Tag>::value, "function_wrapper<_Tag> uses unknown _Tag type" );
};
// Template specilization, that is how we make our implementation differ per tag.
template<>
class function_wrapper<tag_stdcall> : public details::_Function_wrapper_base<tag_thiscall, function_wrapper<tag_thiscall>>
{
public:
function_wrapper( )
: base_type( )
{}
template<typename _Callable>
function_wrapper( _Callable &&f )
: base_type( std::forward<_Callable>( f ) )
{}
template<typename R = void, typename..._Args>
R invoke( _Args&&...args )
{
if ( !base_type::__Empty( ) ) // Notice that we put __stdcall as a function specifier
return (reinterpret_cast<R(__stdcall*)(_Args...)>( base_type::__Target( ) ))( std::forward<_Args>( args )... );
throw std::exception( "function_wrapper<tag_thiscall>::invoke - empty callable object" );
}
void *get_target( )
{
return base_type::__Target( );
}
template<typename _Callable>
void set_target( _Callable &&f )
{
base_type::__Target( std::forward<_Callable>( f ) );
}
};
using stdcall_function = function_wrapper<tag_stdcall>;
using thiscall_function = function_wrapper<tag_thiscall>;
using cdecl_function = function_wrapper<tag_cdecl>;
// not gonna implement the rest, do them yourself!
template<typename _Ty, typename _Ret, typename..._Args>
class member_function
{
public:
using self_type = member_function<_Ty, _Ret, _Args...>;
using value_type = typename std::remove_all_extents<_Ty>::type;
using ptmf_type = _Ret(value_type::*)(_Args...);
member_function( value_type *instance, ptmf_type ptmf )
: this_( instance ), mfn_( ptmf ), unit_( false )
{}
member_function( std::nullptr_t )
: mfn_( ), this_( nullptr ), unit_( true )
{}
member_function( )
: mfn_( ), this_( nullptr ), unit_( true )
{}
template<typename..._Ax>
_Ret invoke( _Ax&&...args )
{
if ( !unit_ )
return (this_->*mfn_)( std::forward<_Ax>( args )... );
throw std::exception( "member_function<_Ty, _Ret, _Args...> empty function" );
}
void set_function( std::nullptr_t )
{
unit_ = true;
}
void set_function( value_type *instance, ptmf_type ptmf )
{
mfn_ = ptmf;
this_ = instance;
}
private:
value_type *this_;
ptmf_type mfn_;
bool unit_;
};