如何返回一个lambda函数?

17

例如,我可以定义一个 lambda 函数:

auto f = [](double value) {double ratio = 100; return value * ratio;}

现在我想生成一个带有比率参数并返回lambda函数的函数,如下所示

auto makeLambda(double ratio) { return [=](double value) {return value * ratio;}; }

如何做到?


1
你现在的代码有什么问题吗? - chris
7
需要使用C++14才能推断函数的返回类型。 - Mike Seymour
3个回答

21

有了 C++14 的函数返回类型推断,那应该可以工作。

在 C++11 中,您可以定义另一个 lambda 表达式(可以推断出返回类型),而不是一个函数(无法推断):

auto makeLambda = [](double ratio) {
    return [=](double value) {return value * ratio;};
};

正如评论中所述,如果你特别想要一个函数,这个可以进一步封装:

auto makeLambdaFn(double ratio) -> decltype(makeLambda(ratio)) {
    return makeLambda(ratio);
}

2
你忘记了捕获内部 lambda。 - Konrad Rudolph
1
该示例在idone中可以运行,但在vc2013中失败了。VC2013仍然不足以支持c++11。 - user1899020
3
如果你需要一个函数而不是lambda函数,可以将lambda函数再次封装在一个函数里:auto func(double x)->decltype(makeLambda(x)){return makeLambda(x);} - Yakk - Adam Nevraumont

12

@免责声明:这个答案只是在@Slava的回答中添加了额外的论点(但对于评论来说太长了)。

你可能不应该返回lambda表达式,而应该返回函数指针或std::function。

除了效率问题(见下文),API的声明应该告诉你如何使用它。Lambda表达式是一种临时函数 - 设计用于在使用它的地方(局部上下文)有意义。

如果你写了这个:

std::function<double( double )> makeFunction(double ratio);

您的代码将变得更加灵活(不依赖于C++14),定义也更好(您可以查看签名并了解其作用),且具有未来可扩展性(易于理解API背后的意图,从而容易进行扩展而不会破坏客户端代码)。

如果您写成这样:

auto makeFunction(double ratio);

你需要在内联定义它(我猜)。

对于类似MikeSeymour答案的实现,您需要添加一个额外的lambda,以避免编译器的限制。阅读一个返回lambda的lambda实现来确定API返回内容是个大忌。

首先,因为它不明显和晦涩难懂。

其次,它将强加给客户端代码一个需要注释/解释说明才能理解的API,或者强迫客户端阅读实现以知道如何使用它。

如果您无法保证这是一次性代码,则会出现以下情况:

  • 增加WTF / SLOC比率(如果需要阅读实现才能弄清楚返回值,则代码的目的不清楚)

  • 有些不明显的东西,您将不得不为整个项目维护。 这称为杂物,这就是使糟糕的旧代码成为糟糕的旧代码的原因。

如果您需要返回functor,最好返回std::function;返回类型几乎大喊“返回functor”。

如果这对您的需求效率太低,可以稍后进行优化/特殊化 - 例如,通过返回struct X { double operator()(double); }实例。

关于能够保证这不是生产代码的说明:

我见过很多情况,例如:

  • 我正在查看三年前的可怕代码,人们告诉我最初这是原型,但我们向客户展示了应用程序,他们要求“按原样”使用它,现在客户端依赖它,但我们没有时间预算来清理它

  • 我将丑陋的原型代码发送给其他人(例如“我们可以做一些遵循此算法的东西”),然后在源代码控制中看到它作为解决方案被提交。

  • 人们编写hack覆盖hack,因为代码已经很糟糕,再加一个hack无所谓(这其实是一个非常常见的借口)。


4
您可以返回std::function<double( double )>类型。调用它可能会增加额外的函数调用成本,在大多数情况下这是微不足道的。

3
如果您也描述一下其含义(主要是效率方面的)的话,这将是一个很好的答案。 - Angew is no longer proud of SO
@Angew,你有关于这方面的信息指针吗?我需要复习一下我的C++11 :) - Joachim Isaksson
7
最大的问题是 std::function 使用了一种称为“类型擦除”的技术,这会导致每次调用都产生一次间接调用(通常实现为虚函数)。 - Simple
@JoachimIsaksson,Simple 的意思就是这样。 - Angew is no longer proud of SO
1
+1;我添加了一个回答,基本上支持这个观点(太长了,不能作为评论)。 - utnapistim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接