【问题标题】:how to deduce return type from lambda?如何从 lambda 推断返回类型?
【发布时间】:2021-10-23 18:00:57
【问题描述】:

这里是示例代码

#include <iostream>

template<typename T>
T foo(T(*fp)())
{
    return fp();
}


int main()
{
    std::cout<<foo([]->int{ return 1; });
}

当我编译上面的代码时,编译器说它不能推导出模板参数, 但我已经指定了 lambda 的返回类型。

【问题讨论】:

  • 您是否尝试过在[] 之前添加+(明确转换lambda -> 函数指针)?
  • 我看到 g++ 和 clang++ 的另一个问题:显式返回类型。应要求在-&gt;int 之前显式使用();所以foo(+[]()-&gt;int{ return 1; });。否则,你可以避免显式返回类型(它是从return 1; 推导出来的),所以foo(+[]{ return 1; });

标签: c++ templates lambda


【解决方案1】:

foo 在您传递 lambda 时采用函数指针,但在 template argument deduction 中不会考虑对 T 进行隐式转换(从 lambda 到函数指针),这会导致调用失败。

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

您可以显式指定模板参数:

foo<int>([]()->int{ return 1; });
// ^^^^^

或者通过operator+static_cast将lambda转换为函数指针。

foo(+[]()->int{ return 1; });
//  ^
foo(static_cast<int(*)()>([]()->int{ return 1; }));
//  ^^^^^^^^^^^^^^^^^^^^^^                    ^

顺便说一句:与尾随返回类型一起使用的省略参数列表是 C++23 lambda 功能。 (所以我添加了()s。)正如@max66 建议的那样,没有尾随返回类型,lambda 也可以正常工作;返回类型会自动推导出来,比如foo(+[]{ return 1; });

【讨论】:

  • 对于您的代码,clang-cl 给出:error : lambda requires '()' before return type。删除()[] 之后)是 C++20 的事情吗? MSVC 给出了类似的错误消息。
  • @AdrianMole - 来自 g++ 的相同错误,编译 C++17(我很惊讶:我不知道这个要求)。
  • 是的,如果您使用 GCC11 构建,错误消息是“在 lambda 尾随返回类型之前的参数声明仅可选 '-std=c++2b' 或 '-std=gnu++2b' "
  • Clang-cl 设置为使用 C++20 会给出相同的错误消息。 MSVC 是否设置为使用“最新”(C++23??)
  • @AdrianMole max66 是的,它是 C++23 lambda 功能。 省略的参数列表:函数不带任何参数,就好像参数列表是()。仅当未使用 constexpr、consteval、mutable、异常规范、属性或尾随返回类型时,才能使用此形式。 (C++23 前)
【解决方案2】:

如果您不想更改调用站点,您可以随时更改 foo 以便它可以使用 lambda:

template<typename F>
std::invoke_result_t<F> foo(F&& f)
{
    return f();
}

另请注意,您的 lambda 目前仅适用于 C++23 - 如果您希望它在任何地方都可以使用,请添加(空)参数列表:

[]()->int{ return 1; }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 2013-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    相关资源
    最近更新 更多