从 lambda 构建 std::function 参数

Constructing std::function argument from lambda

我有以下模板函数(编译器中启用了 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并且能够推导参数和return类型。

然而在第二种情况下,它应该(?)也知道 lambda 应该被转换成一些 std::function,但仍然无法做到。

有没有办法得到第二个运行?还是模板根本不会自动转换?

错误信息是:

error C2672: 'MyFunction': no matching overloaded function found

error C2784: 'void MyFunction(const std::function<_Ret(_Types...)> &)': could not deduce template argument for 'const std::function<_Ret(_Types...)>

note: see declaration of '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,我将如何推导出参数包和 return 值?有没有办法通过一些“可调用特征”从可调用对象中获取它?

Or can it be that for templates the automatic conversion does not take place at all?

是的。 template argument deduction.

中不考虑隐式转换

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

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

作为解决方法,您可以

  1. 如您所示使用显式转换
  2. 正如所建议的那样,只需为仿函数使用一个模板参数。例如

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