从 lambda 构造 std::function 参数

我有以下模板化函数(编译器中启用了 C++ 最新标准 - 但也许 17 个就足够了).

#include 模板void MyFunction(const std::function& callback);int main(){MyFunction(std::function([](int){}));MyFunction([](int){});}

第一个调用编译,当我将它显式转换为 std::function 时,但第二种情况没有.

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

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

有没有办法让第二个运行?或者是因为模板根本不进行自动转换?

错误信息是:

<块引用>

错误 C2672:'MyFunction':找不到匹配的重载函数

错误 C2784:'void MyFunction(const std::function<_Ret(_Types...)> &)':无法推导出 'const std::function<_Ret(_Types...) 的模板参数>

注意:见'MyFunction'的声明

我的目标是python 风格的装饰器".所以基本上是这样的:

templateauto MyFunction(std::function&& callback) ->std::function{return [callback = std::move(callback)](TArgs...args)->TReturn{返回回调(std::forward(args)...);};}

如果我使用模板而不是 std::function,我将如何推导出参数包和返回值?有没有办法通过一些可调用特征"从可调用对象中获取它?

解决方案

或者是因为模板根本不进行自动转换?

是的.模板参数推导不会考虑隐式转换.><块引用>

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

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

作为解决方法,您可以

  1. 使用显示的显式转换
  2. 正如 评论所建议的那样,只需使用函子的单个模板参数.例如

    templateauto MyFunction2(F&&回调){return [callback = std::move(callback)](auto&&... args){return callback(std::forward(args)...);};}

I have the following templated function (C++ latest standard is enabled in the compiler - but maybe 17 would be enough).

#include <functional>

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

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

The first call compiles, when I explicitly convert it to std::function, but the second case does not.

In the first case the template deduction is done automatically, the compiler only knows that it shall convert it to some std::function and able to deduce the parameter and return type.

However in the second case it shall(?) also know that the lambda shall be converted to some std::function, but still unable to do it.

Is there a solution to get the second one running? Or can it be that for templates the automatic conversion does not take place at all?

The error message is:

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'

What I am aiming for is a "python style decorator". So basically this:

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)...);
    };
}

If I used a template instead of std::function, the how would I deduce the parameter pack and return value? Is there some way to get it from a callable via some "callable traits"?

解决方案

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

Yes. Implicit conversions won't be considered in 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.

That means given MyFunction([](int){});, the implicit conversion (from lambda to std::function) won't be considered, then the deduction for TReturn and TArgs fails and the invocation attempt fails too.

As the workarounds, you can

  1. Use explicit conversion as you showed
  2. As the comment suggested, just use a single template parameter for functors. e.g.

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

相关文章