定义lambda的一般准则

时间:2013-11-26 10:19:45

标签: c++ c++11 lambda

现在我们可以在代码库中使用C ++ 11 lambdas,我们正在努力解决如何定义和使用它们的一般原则。我意识到这肯定存在主观因素,但我认为也可能有一些更为一般的经验法则对社区有用。

定义lambda的一般原则是什么?

  • 您何时应该参考[&]或价值[=]?性能影响是什么?
  • 您何时应该明确地捕获变量,例如[&foo]
  • 在什么情况下你应该指定一个返回类型? (C ++ 14对推断返回类型的支持比C ++ 11更好)
  • lambda在被重写为函数之前有多复杂?

就个人而言,我目前的一般原则是'只要你需要一个简单的谓词或比较器'就使用lambda,但这可能意味着我错过了一些更强大的用例。

4 个答案:

答案 0 :(得分:2)

其中许多问题的答案都是基于程序员的品味和代码风格。

  

您何时应该通过引用[&]或值[=]进行捕获?性能影响是什么?

当您想要更改传递的对象或者您不想复制时,您将按&捕获。否则,您可以按=进行捕获。

  

您何时应该明确地捕获变量,例如[& foo]?

如果您只想捕获使用[&foo]的特定对象,则可以通过传递特定对象而非[&]来避免意外错误,从而使您的代码更具限制性。

  

在什么情况下你应该指定一个返回类型?

您将在需要时确定返回类型(C ++ 11)。没有特别的建议。

  

lambda在被重写为函数之前有多复杂?

如果您认为函数对于在许多函数中重用是有用的,则应将其写为 正常的功能。 Lambda通常对解决当地需求很有用。

  

无论何时需要简单的谓词或比较器,都要使用lambda

是。谓词或比较器功能不再被重用是使用lambdas的流行案例。

答案 1 :(得分:2)

这些问题有些主观,但我会试一试:

  • 当你需要修改封闭范围内的值时(显然),或者当你想避免复制重变量时,通过引用捕获;否则按值捕获。

  • 如果您需要在封闭范围内修改它的值,而不是其他变量的值,则通过引用捕获特定变量。

  • 我尝试始终指定返回类型以提高可读性(因此其他人可以立即知道返回类型,而不必解析lambda来推断它)。

  • 最后一个是最主观的,但我个人认为大于~3-5行的lambdas应该重构为函数,因为长lambdas会降低可读性。但是,可能存在许多例外情况,因此这取决于个人偏好,并且在很大程度上取决于实际代码。

答案 2 :(得分:1)

除了其他答案。

  

无论何时需要简单的谓词或比较器,都要使用lambda

另一个有用的模式是初始化const个变量。在lambdas之前,当一个变量的初始化变得太复杂而不适合单个表达式时,你要么删除constness,要么写一个只使用一次的单独函数(这有其他问题,比如必须从原来传递参数)范围)。

考虑以下愚蠢的,极其简化的示例(假设x的初始化不能重写为单个表达式,因为if部分太复杂):

void foo(int y) {
    int x = 42;
    if (y > 42)
        ++x;
    // from now on we mustn’t change x any more
    // but unfortunately it's not const
    // use x
}

// or

int init_x(int y) {
    // this function is only used once to initialize x in foo()
    // we could have many more parameters (not just y)
    int x = 42;
    if (y > 42)
        ++x;
    return x;
}
void foo(int y) {
    const int x = init_x(y);
    // use x
}

现在使用lambdas你可以摆脱额外的功能,参数传递,但仍然保持常量:

void foo(int y) {
    const int x = [&]() {
            int x = 42;
            if (y > 42)
                ++x;
            return x;
        }();
    //   ^^ note: we call the lambda immediately
    // use x
}

当然,这仍然遵循关于我们是否可以内联编写代码或者我们应该创建单独函数的通常“规则”。但这很好地解决了那些(很多!)情况,其中初始化代码足够复杂,必须删除常量,但不够复杂,无法证明单独的函数。

答案 3 :(得分:0)

关于你的上一个问题: lambda函数本质上是一个内联定义的匿名函数(没有名称的函数)。当你需要一个似乎不能证明和定义正常函数的小函数时,它非常有用。 lambda函数很方便的典型示例是将比较传递给std :: sort。例如:

struct Apple
{
   Apple(double weight, int age) :
      m_weight(weight),
      m_age(age)
   {}

   double m_weight; 
   int m_age; 
};

int main()
{
   vector<Apple> myApples;
   myApples.push_back(Apple(0.30, 30));
   myApples.push_back(Apple(0.75, 80));
   myApples.push_back(Apple(0.55, 90));

   sort(myApples.begin(),
        myApples.end(),
        [](const Apple &a, const Apple &b) -> bool
        {
           return (a.m_weight < b.m_weight);
        });

   return 0;
}