首页 > 解决方案 > Constructing std::function argument from lambda

问题描述

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"?

标签: c++templateslambdastltemplate-argument-deduction

解决方案


或者可能是模板根本不进行自动转换?

是的。模板参数推导中不会考虑隐式转换。

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

这意味着 given ,将不考虑MyFunction([](int){});隐式转换(从 lambda 到),然后推论and失败并且调用尝试也失败。std::functionTReturnTArgs

作为解决方法,您可以

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

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

推荐阅读