vendredi 29 mars 2019

generate lambdas body (that invokes a callable and returns) depending on template type

I have a callable object that might return bool or void. This object needs to be wrapped in a lambda. This lambda should always return bool. If the callable object returns bool then lambda return whatever is returned by the object. Otherwise (if object returns void) lambda just invokes it and returns true.

I tried to simplify the code below as much as possible.

template<class... Params>
struct SParamsPack {};

template <class T> struct SFuncInfo {};

// in the simplified version specialization only for member function
template <class T, class R, class... FuncParams>
struct SFuncInfo<R(T::*)(FuncParams...)> {
    using Signature = std::function<bool(FuncParams...)>;
    using Ret = R;
    using Params = SParamsPack<FuncParams...>;
};

template<class T, class Func, class... Params>
SFuncInfo<Func>::Signature GenerateVoidLambda(Func f, T* pObj, SParamsPack<Params...>)
{
    return [pObj, f](Params&&... params) -> bool
    {
        std::invoke(f, pObj, std::forward<Params>(params)...);
        return true;
    };
}

template<class T, class Func, class... Params>
SFuncInfo<Func>::Signature GenerateBoolLambda(Func f, T* pObj, SParamsPack<Params...>)
{
    return [pObj, f](Params&&... params) -> bool
    {
        return std::invoke(f, pObj, std::forward<Params>(params)...);
    };
}

// bodies of both WrapMemberFunction are almost identical
template<class T, class Func, std::enable_if_t<std::is_same<typename SFuncInfo<Func>::Ret, bool>::value, bool> = true>
SFuncInfo<Func>::Signature WrapMemberFunction(Func f, T* pObj)
{
    return GenerateBoolLambda(f, pObj, SFuncInfo<Func>::Params());
}

template<class T, class Func, class = std::enable_if_t<std::is_same<typename SFuncInfo<Func>::Ret, void>::value>>
SFuncInfo<Func>::Signature WrapMemberFunction(Func f, T* pObj)
{
    return GenerateVoidLambda(f, pObj, SFuncInfo<Func>::Params());
}

//! Registers a std::function that returns bool.
template<class... Params>
void RegisterCommand(const string& id, std::function<bool(Params...)> f)
{
    // Code for registration of command.
}

//! Registers a member function pointer as a command.
template<class T, class Func>
void RegisterCommand(const string& id, Func f, T* pObj)
{
    RegisterCommand(id, CommandRegistry::WrapMemberFunction(f, pObj));
}

The user's call would look like this:

RegisterCommand("general.create", &SomeObj::OnCreate, pSomeObject);

So is there any way to make this code look nicer? Is it possible to get rid of at least of WrapMemberFunction or GenerateLambda methods?

Any other tips on how to simplify this code are much appreciated.

Aucun commentaire:

Enregistrer un commentaire