从Lambda构造std :: function参数

时间:2019-02-13 06:59:06

标签: c++ templates lambda stl template-deduction

我具有以下模板化功能(在编译器中启用了C ++最新标准-但也许17足够了)。

#include <functional>

template<typename TReturn, typename ...TArgs>
void MyFunction(const std::function<TReturn(TArgs...)>& callback);

int main()
{
    MyFunction(std::function([](int){}));
    MyFunction([](int){});
}

当我将其显式转换为std :: function时,第一个调用会编译,但是第二种情况不会。

在第一种情况下,模板推导是自动完成的,编译器只知道它将其转换为某种std :: function并能够推导参数和返回类型。

但是,在第二种情况下,它也应该知道将lambda转换为某些std :: function,但仍然无法执行。

是否有一种解决方案可以运行第二个?还是对于模板而言,根本就不会发生自动转换?

错误消息是:

  

错误C2672:“ MyFunction”:未找到匹配的重载函数

     

错误C2784:'无效的MyFunction(const std :: function <_Ret(_Types ...)>&)':无法推断'const std :: function <_Ret(_Types ...)>的模板参数/ p>      

注意:请参见“ MyFunction”的声明

我想要的是一个“ python样式装饰器”。所以基本上是这样:

template<typename TReturn, typename ...TArgs>
auto MyFunction(std::function<TReturn(TArgs...)>&& callback) -> std::function<TReturn(TArgs...)>
{
     return [callback = std::move(callback)](TArgs... args)->TReturn
     {
          return callback(std::forward<TArgs>(args)...);
    };
}

如果我使用模板而不是std :: function,我将如何推断参数包和返回值?是否可以通过一些“可调用特征”从可调用对象中获取它?

1 个答案:

答案 0 :(得分:4)

  

对于模板来说,根本就不会自动转换吗?

是的。在template argument deduction中不会考虑隐式转换。

  

类型推导不考虑隐式转换(上面列出的类型调整除外):这是超载解析的工作,稍后会发生。

这意味着在给定MyFunction([](int){});的情况下,将不考虑隐式转换(从lambda到std::function),然后对TReturnTArgs的推论失败,并且调用尝试也失败。

作为解决方法,您可以

  1. 使用显示的显式转换
  2. 根据the comment的建议,仅对函子使用单个模板参数。例如

    template<typename F>
    auto MyFunction2(F&& callback)
    {
         return [callback = std::move(callback)](auto&&... args)
         {
              return callback(std::forward<decltype(args)>(args)...);
         };
    }