在C++中调用lambdas的方式是最常用的

Which way of invoking lambdas in C++ is the most idiomatic?

本文关键字:方式 常用 lambdas C++ 调用      更新时间:2023-10-16

我注意到lambdas既使用函数指针工作,也使用g++的专用function类型工作。

#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); 
}

我的问题是:以下哪一个最常用?使用一个比另一个有什么危险和/或好处?

我注意到lambdas都使用函数指针以及专用的function类型

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

以下哪一个最常用?

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

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

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

使用一个比另一个有什么危险和/或好处?

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

我会说(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::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