我有一个可调用对象,该对象可能返回bool
或void
。该对象需要包装在lambda中。此lambda应始终返回bool
。如果可调用对象返回bool
,则lambda返回该对象返回的所有内容。否则(如果对象返回void
),lambda只会调用它并返回true
。
我试图尽可能简化下面的代码。
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
{
(pObj->*f)(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 (pObj->*f)(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));
}
用户的呼叫将如下所示:
RegisterCommand("general.create", &SomeObj::OnCreate, pSomeObject);
代码应符合C ++ 14标准。
那么有什么办法可以使这段代码看起来更好呢?是否有可能至少摆脱WrapMemberFunction()
或GenerateLambda()
方法?
非常感谢您提供有关简化此代码的其他提示。
答案 0 :(得分:2)
没有很好的解决方案...
我能想象的最好的是一个带有if constexpr
的lambda来分隔两种情况(您标记了C ++ 11,但您使用的是std::invoke()
,所以您使用的是C ++ 17,因此您也可以使用if constexpr
)
template <typename T, typename F, typename ... Args>
typename SFuncInfo<F>::Signature GenerateLambda(F f, T* pObj,
SParamsPack<Args...>)
{
return [pObj, f](Args && ... as) -> bool
{
if constexpr ( std::is_same_v<void,
decltype(std::function{f})::result_type> )
{
std::invoke(f, pObj, std::forward<Args>(as)...);
return true;
}
else
return std::invoke(f, pObj, std::forward<Args>(as)...);
};
}
答案 1 :(得分:2)
好吧...如果您不能使用C ++ 17(因此没有std::function
的模板推导指南,也没有if constexpr
的模板推论),我能想象的最好是定义两个重载函数来接收对象,该对象的方法指针和该方法的参数。
template <typename T, typename ... As1, typename ... As2>
bool callFunc (T * pObj, bool(T::*f)(As1...), As2 && ... args)
{ return (pObj->*f)(std::forward<As2>(args)...); }
template <typename T, typename ... As1, typename ... As2>
bool callFunc (T * pObj, void(T::*f)(As1...), As2 && ... args)
{ (pObj->*f)(std::forward<As2>(args)...); return true; }
如您所见,第一个返回方法返回的值(一个bool
值);第二个调用方法(返回void
)并返回true
。
鉴于这对callFunc()
,您可以按照以下步骤创建一个GenerateLambda()
template <typename T, typename F, typename ... As>
typename SFuncInfo<F>::Signature GenerateLambda (F f, T * pObj,
SParamsPack<As...>)
{
return [pObj, f](As && ... args)
{ return callFunc(pObj, f, std::forward<As>(args)...); };
}