我想创建一个函数,它将lambda,std :: function或regular函数作为输入,并将其包装成类似下一个函数的东西:
void original_function(const int x, float y) {
// do smth ...
}
...
using WrapperType = std::function<void(const QVariantList &)>;
WrapperType original_function_wrapper = [original_function](const QVariantList &vl) {
original_function(vl.value(0).value<int>(), vl.value(1).value<float>());
};
所以我创建了一些助手来处理我的问题:
template<size_t index, typename T>
T unpackFromVariant(const QVariantList &v) {
return qvariant_cast<T>(v.value(static_cast<int>(index)));
};
template<typename T>
struct function_traits;
template<typename Ret, typename... Args>
struct function_traits<Ret(Args...)> {
enum { ArgumentCount = sizeof...(Args) };
using ArgumentTypes = std::tuple<Args...>;
using ReturnType = Ret;
};
template<typename Ret, typename... Args>
struct function_traits<std::function<Ret(Args...)>> {
enum { ArgumentCount = sizeof...(Args) };
using ArgumentTypes = std::tuple<Args...>;
using ReturnType = Ret;
};
template<size_t index, typename T>
struct type_of {
using Type = typename std::remove_reference<decltype(std::get<index>(T()))>::type;
};
using WrapperFunctionType = std::function<void(const QVariantList &)>;
template<typename FT, typename T, size_t... I>
WrapperFunctionType createWrapperImpl(T &&functor, std::index_sequence<I...>) {
return [ff = std::forward<T>(functor)](const QVariantList &vl) {
ff(unpackFromVariant<I, typename type_of<I, typename FT::ArgumentTypes>::Type>(vl) ...);
};
};
template<typename T>
WrapperFunctionType createWrapper(T &&functor) {
using TT = typename std::remove_reference<T>::type;
using FunctionTraits = function_traits<TT>;
using Indices = std::make_index_sequence<FunctionTraits::ArgumentCount>;
return createWrapperImpl<FunctionTraits>(std::forward<T>(functor), Indices());
}
它适用于std::function
和常规函数,但它对lambdas没用(这意味着每次我想传递lambda函数作为参数时,我必须首先用std::function(RET_VAL(ARGS))
包装它)。有没有办法专门化function_traits
模板来推导lambda参数类型?
答案 0 :(得分:1)
我会从:
开始template<class...Args, class F>
std::result_of_t<F(Args&&...)>
apply_variant( F&& f, QVariantList& list ){
auto indexer=index_upto<sizeof...(Args)>();
return indexer([&](auto...Is)->decltype(auto){
return std::forward<F>(f)( list.value(Is).value<Args>()... );
};
}
其中here为index_upto
。
现在我们退后一步:
template<class...Args, class F>
WrapperFunctionType createWrapper(F&& f){
return [f=std::forward<F>(f)](auto& list)mutable->decltype(auto){
return apply_variant<Args...>( f, list );
};
}
template<class R, class...Args>
WrapperFunctionType createWrapper(std::function<R(Args...)> f){
return [f=std::move(f)](auto& list)mutable->decltype(auto){
return apply_variant<Args...>( f, list );
};
}
template<class R, class...Args>
WrapperFunctionType createWrapper(R(*f)(Args...)){
return [f=std::move(f)](auto& list)mutable->decltype(auto){
return apply_variant<Args...>( f, list );
};
}
现在,这个版本你必须传递你期望用函数对象调用的类型。
我们可以做一个不明智的人:
namespace details{
template<class T>struct tag_t{};
template<class...Args, class R, class U, class F>
WrapperFunctionType createWrapper(tag_t<R(U::*)(Args...)>, F&& f){
return [f=std::forward<F>(f)](auto& list)mutable->decltype(auto){
return apply_variant<std::remove_reference_t<Args>...>( f, list );
};
}
}
template<class F>
WrapperFunctionType createWrapper(F&& f){
using dF=std::decay_t<F>;
using sig_t = details::tag_t<decltype(&dF::operator())>;
return details::createWrapper( sig_t{}, std::forward<F>(f) );
}
或某些。
代码未编译。