使用C++11 lambda表达式提高代码可读性

8

我非常喜欢lambda函数,并且在C++中使用它们的能力是一种享受。但是,由于我习惯了Haskell,那里lambda函数非常适合语法,所以我很难在C++中使用它们而不编写难以阅读的混乱冗长的代码行。

因此,例如,假设我要编写以下内容:

vector<double> foo(10,0.2);
for_each(foo.begin(), foo.end(), [](double x){ std::cout << x << " ";})

这段代码并不难读,lambda表达式非常简短。但是如果在for_each中嵌套了两到三行的函数,那么这将成为我阅读代码的障碍:

vector<double> foo(10,0.2);
randomNumberGenerator bar;
for_each(foo.begin(), foo.end(), [](double x){ std::cout << "hello!"; x+=bar()/(1+bar()); std::cout << x << " ";})
//sorry, I couldn't think of a less stupid example... 

这一行文字变得令人厌烦,读起来也变得困难了...

在这种情况下,您更喜欢使用哪种代码约定?我应该写:

for_each(foo.begin(), foo.end(), 
          [] (double x) {
                std::cout << "hello!"
                x += bar()/(1+bar());
                std::cout << x << " ";
          });

或者类似这样的语法?我仍然认为这种语法感觉有点不自然且难以阅读... :(

1
我喜欢最后一个选项,只是你把左大括号放错了位置。 :-) - Bo Persson
1
为什么这不是“主观和争议性的”? - Johannes Schaub - litb
如果你想让它更短,也可以使用boost range,它只需要将容器作为第一个参数。(boost::for_each(foo, {...});) - Viktor Sehr
有趣的是,这正是我在我的问题中所做的,希望能够更好地阅读。 - Keugyeol
6个回答

10

我通常选择

for_each(foo.begin(), foo.end(), [](double x) {
    std::cout << "hello!"
    x += bar()/(1+bar());
    std::cout << x << " ";
});

我写了几百行的lambda函数。


2
+1:我还没有写过太多的lambda表达式,但是从学习它们时阅读它们的经验来看,它们常常看起来像循环或其他块的主体。在这些情况下,将lambda代码放在一行内与将您的循环代码放在一行内一样自然。我认为您应该使用相同的原因来移动lambda内容以外(或不移动内容以外),就像处理其他循环主体一样。 - Michael Burr

6

如果您愿意,您可以使用auto单独命名lambda:

auto const baz = [](double x)
{
    std::cout << "hello!"
    x += bar()/(1+bar());
    std::cout << x << " ";
};
std::for_each(foo.begin(), foo.end(), baz);

1
出于好奇,为什么在lambda声明中使用auto const中的const - Phlucious
1
@Phlucious: 我有一个“尽可能使用const”的心态,这可能是个习惯。对于lambda表达式来说,这当然不是必要的,没有任何隐藏惊喜。 :-] - ildjarn

4

Hmm...

for_each(foo.begin(), foo.end(), 
    [] (double x)
    {
        std::cout << "hello!"
        x += bar()/(1+bar());
        std::cout << x << " ";
    });

for (auto x : foo)
{
    std::cout << "hello!";
    x += bar()/(1+bar());
    std::cout << x << " ";
}

1
也许除了for_each之外的算法在这里会更好,但是对我来说,在这里使用for循环更自然。 - Keith Layne

2

我认为Lambda表达式就是另一种函数声明方式,因此,在合理的范围内,我遵循其他函数的相同约定:

// when lambdas are present, I break the enveloping method params
for_each(
  foo.begin(), 
  foo.end(),           
  [] (double x)
  // I also like to split the brackets, just like with any function
  {
     std::cout << "hello!" 
     x += bar()/(1+bar());                
    std::cout << x << " ";          
  }); // the closing parenthesis is left with the closing bracket

1

发布我的

std::vector<int> a;
std::find_if(a.begin()
           , a.end()
           , [&](int i)
             {
                 return i == 0;
             });

1
我认为,如果Lambda表达式的代码超过一到两个语句,那么它应该是一个单独的命名函数。

5
只有在您打算在其他地方重复使用代码时,才需要这样做。 - Puppy
1
在我看来,如果你想让代码可读性强、易于理解和易于测试,这是必要的。 - user2100815
一个命名的lambda比一个命名的函数不易读?这就是主观性的极致了。 - ildjarn
2
@ildjarn 我说过那个吗?哦,看起来我没有!我说一个命名函数比一个lambda更易读。大多数人会认为这意味着一个未命名的函数。但无论如何,是的。我相信命名函数比命名lambda更清晰,我怀疑99%的C++程序员会和我一样。叹气。我们经历了模板误用的恐惧 - 我想我们现在必须再次经历它与lambda。 - user2100815

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