【问题标题】:Which way of invoking lambdas in C++ is the most idiomatic?在 C++ 中调用 lambda 的哪种方式最惯用?
【发布时间】:2014-11-05 10:26:07
【问题描述】:

我注意到 lambda 既可以使用函数指针,也可以使用专用的 function 类型使用 g++

#include <functional>

typedef int(*fptr)(int, int);

int apply_p(fptr f, int a, int b) {
  return f(a, b);
}

int apply_f(std::function<int(int, int)> f, int a, int b) {
  return f(a, b);
}

void example() {
  auto add = [](int a, int b) -> int {
    return a + b;
  };

  apply_p(add, 2, 3); // doesn't give an error like I'd expect it to
  apply_f(add, 2, 3); 
}

我的问题是:哪些是最习惯使用的?使用其中一种有哪些危险和/或好处?

【问题讨论】:

  • 今天问的this question相关。仅当 lambda 没有捕获时,转换为函数指针才有效。作为我的回答,还有另一种选择,使用模板并将 lambda 视为可调用。 std::function 会产生开销,并且无法像 lambda 那样优化。
  • 第二个版本可能会产生不必要的开销。我会将apply_f 设为函数模板。
  • @ShafikYaghmour wow.. 随机时间
  • @juanchopanza 所说的是 imo 最好的建议:不必关心函数指针语法,没有 std::function 的性能开销,它适用于你抛出的与调用匹配的所有内容 - 包括“原始”函数、std::functions、lambdas、您自己的运算符类

标签: c++ lambda function-pointers


【解决方案1】:

我注意到 lambdas 既可以使用函数指针也可以使用专用的function 类型

如果 lambda 没有捕获任何内容,那么它可以衰减为函数指针。

哪些是最常用的?

两者都没有。如果要存储任意可调用对象,请使用 function。如果您只想创建和使用一个,请保持通用:

template <typename Function>
int apply(Function && f, int a, int b) {
     return f(a,b);
}

您可以更进一步,将返回值和参数类型设为通用;我会把它留作练习。

使用其中一种有什么危险和/或好处?

函数指针版本仅适用于(非成员或静态)函数和非捕获 lambda,并且不允许传递任何状态;只有函数本身及其参数。 function 类型可以包装任何可调用的对象类型,无论有无状态,因此更普遍有用。然而,这有一个运行时成本:隐藏包装类型,调用它会涉及到一个虚函数调用(或类似的);并且它可能需要动态内存分配来保存大类型。

【讨论】:

  • 保持它那个通用不是很危险吗?这样做不会完全失去所有类型安全吗?
  • @ElectricCoffee:我没有看到任何危险,而且它当然不会失去 all 类型的安全性。它允许使用f(a,b) 是可转换为int 的格式良好的表达式的任何类型。其他类型将被拒绝。
【解决方案2】:

我会说 (C++14)

template <class Functor, class... Args>
decltype(auto) apply_functor(Functor&& f, Args&&... args) {
    return std::forward<Functor>(f)(std::forward<Args>(args)...);
}

或 C++11:

template <class Functor, class... Args>
auto apply_functor(Functor&& f, Args&&... args) ->decltype(std::forward<Functor>(f)(std::forward<Args>(args)...)) {
    return std::forward<Functor>(f)(std::forward<Args>(args)...);
}

【讨论】:

  • 您可以考虑将其设为 std::forward&lt;Functor&gt;(f)(std::forward&lt;Args&gt;(args)...); 以保留 f 参数的值类别。
  • @Niall 谢谢,已修复。还将 C++14 版本的 auto 更改为 decltype(auto) 以支持通过引用返回。
【解决方案3】:

如果有疑问,请首选std::function

  1. 语法更直接且与其他类型一致,例如

    typedef std::function<int (int, int)> MyAddFunction;
    

    typedef int (*MyAddFunction)( int, int );
    
  2. 它更通用(它实际上可以采用 lambda 或普通 C 函数或仿函数)

  3. 类型更安全

    apply_p(0, 0, 0); // probably crashes at runtime, dereferences null pointer
    apply_f(0, 0, 0); // doesn't even compile
    

【讨论】:

  • apply_fapply_p 是什么?
  • @AdriC.S.问题中定义的函数。
  • @MikeSeymour 是的,但我的意思是哪一个:apply_f 是函数,apply_p 是指针?
  • @AdriC.S.:是的,这就是问题中的定义。
  • @AdriC.S.感谢您的评论,他们让我意识到我实际上把它们弄混了——apply_p 在调用 0 时会崩溃。 :-) 我想这就是为什么我的答案是 -1 的原因?
猜你喜欢
  • 2018-03-09
  • 2014-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多