C++ lambdas和std::函数的包装器

C++ lambdas和std::函数的包装器,c++,templates,lambda,c++14,C++,Templates,Lambda,C++14,我想创建一个函数,它以lambda、std::function或常规函数作为输入,并将其包装成类似于下一个函数的形式: void original_function(const int x, float y) { // do smth ... } ... using WrapperType = std::function<void(const QVariantList &)>; WrapperType original_function_wrapper = [ori

我想创建一个函数,它以lambda、std::function或常规函数作为输入,并将其包装成类似于下一个函数的形式:

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>());
};
void原始函数(常量int x,浮点y){
//做smth。。。
}
...
使用WrapperType=std::function;
WrapperType原始_函数_wrapper=[原始_函数](常量QVariantList&vl){
原始函数(vl.value(0.value(),vl.value(1.value());
};
因此,我创建了几个助手来处理我的问题:

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());
}
模板
T解压变量(常量QVariantList&v){
返回qvariant_cast(v.value(静态_cast(索引));
};
模板
结构功能特征;
模板
结构功能特性{
枚举{ArgumentCount=sizeof…(Args)};
使用ArgumentTypes=std::tuple;
使用ReturnType=Ret;
};
模板
结构功能特性{
枚举{ArgumentCount=sizeof…(Args)};
使用ArgumentTypes=std::tuple;
使用ReturnType=Ret;
};
模板
结构类型{
使用Type=typename std::remove_reference::Type;
};
使用WrapperFunctionType=std::function;
模板
WrapperFunctionType createWrapperImpl(T&&functor,std::index_序列){
返回[ff=std::forward(函子)](常量QVariantList&vl){
ff(变型(vl)…);
};
};
模板
WrapperFunctionType createWrapper(T&&functor){
使用TT=typename std::remove_reference::type;
使用FunctionTraits=功能特性;
使用index=std::生成索引序列;
返回createWrapperImpl(std::forward(functor),index());
}
它适用于
std::function
和常规函数,但对lambdas无效(这意味着每次我想将lambda函数作为参数传递时,我必须首先用
std::function(RET_VAL(ARGS))
将其包装起来)。有没有什么方法可以专门化
函数\u traits
模板来推断lambda参数类型?

我将从以下内容开始:

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>()... );
  };
}
现在,在这个版本中,您必须传递希望调用函数对象的类型

我们可以做一件不明智的事:

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) );
}
名称空间详细信息{
templatestruct标记{};
模板
WrapperFunctionType createWrapper(标记t、F和F){
返回[f=std::forward(f)](自动和列表)可变->decltype(自动){
返回应用变量(f,列表);
};
}
}
模板
包装器FunctionType createWrapper(F&&F){
使用dF=std::decation\u t;
使用sig\u t=details::tag\u t;
返回详细信息::createWrapper(sig_t{},std::forward(f));
}
或者类似的


代码未编译。

它应该如何处理[&](自动&&…args){return sizeof…(args);}?通常,lambda和函数对象没有固定的签名;假设他们这样做通常是个坏主意。如果有可能推断固定签名,只需从
template struct function\u traits:function\u traits{}开始之类的。谢谢您的回复。在我的代码中,我刚刚添加了
struct function\u traits
,然后按照您前面的建议添加了
struct function\u traits:public function\u traits
,解决了一个问题。
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) );
}