【问题标题】:Constructing std::function argument from lambda从 lambda 构造 std::function 参数
【发布时间】:2019-07-06 22:32:33
【问题描述】:

我有以下模板函数(编译器中启用了 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: 'void MyFunction(const std::function<_ret> &)': 无法推导出 'const std::function<_ret>

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

【问题讨论】:

  • 您遇到什么错误?请编辑您的问题以包括它们(完整和完整)。
  • 根据用例和设计,您可以通过对可调用对象本身使用单一模板类型来绕过此问题,如template&lt;typename F&gt; void MyFunction(F callback);
  • 旁注,不要将 std:: 函数与模板一起使用,使 lambda 类型为模板参数并通过 std::is_invokable (如果相关)进行约束
  • 谢谢大家。查看我更新的问题

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


【解决方案1】:

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

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

【讨论】:

  • 我已经编辑了我的问题,使其更加具体,我的目标是什么
  • 没有从 lambda 到 std::function 的隐式转换,是吗?但是,非捕获 lambda 隐式转换为函数指针,该函数指针又可用于初始化 std::function。我弄错了吗?
  • @KrzysiekKarbowiak std::function 有一个 converting constructor(第 5 个)。
  • @songyuanyao,我不应该在喝完第一杯咖啡之前发布 cmets。我怎么会错过从我多次使用的可调用对象(lambda 是)构造std::function,而只想通过函数指针构造?
  • 现在可以使用了,谢谢。 JVAPen 建议使用 std::is:invocablem 但 static_assert(std::is_invocable::value, "Wrapped object must be invocable") 来检查类型;总是给出 false 并且断言失败
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2018-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多