对于使用lambdas在C ++中执行嵌套函数,每个人都有什么看法?例如,而不是:
static void prepare_eggs()
{
...
}
static void prepare_ham()
{
...
}
static void prepare_cheese()
{
...
}
static fry_ingredients()
{
...
}
void make_omlette()
{
prepare_eggs();
prepare_ham();
prepare_cheese();
fry_ingredients();
}
你这样做:
void make_omlette()
{
auto prepare_eggs = [&]()
{
...
};
auto prepare_ham = [&]()
{
...
};
auto prepare_cheese = [&]()
{
...
};
auto fry_ingredients = [&]()
{
...
};
prepare_eggs();
prepare_ham();
prepare_cheese();
fry_ingredients();
}
来自通过使用Pascal学习如何编码的一代,嵌套函数对我来说非常有意义。但是,在代码审查期间,这种用法似乎让我工作组中一些经验不足的开发人员感到困惑,因为我以这种方式使用了lambdas。
答案 0 :(得分:11)
我没有看到嵌套函数本身有什么问题。我将lambdas用于嵌套函数,但前提是它满足某些条件:
所以在你的例子中,我不会将lambdas用作第一个原因。
从概念上讲,嵌套函数可能与类中私有方法有用的原因相同。它们强制执行封装,并且可以更轻松地查看程序的结构。如果函数是某个其他函数的实现细节,那么为什么不明确地这样做呢?
我看到的最大问题是可读性;读取具有大量嵌套和缩进的代码更加困难。此外,人们对lambdas不太满意,但预计会有抵抗力。
答案 1 :(得分:6)
对于任何给定的代码,请将视为必要可见,尽可能隐藏:
答案 2 :(得分:3)
您已经可以通过收到的评论猜测您正在做一些非正统的事情。这是C ++声名狼借的原因之一,人们永远不会停止滥用它。 Lambdas主要用作标准库算法的内联函数对象和需要某种回调机制的场所。我认为这涵盖了99%的用例,它应该保持这种状态!
正如Bjarne在他的一个讲座中所说:“并非一切都应该是一个模板,而不是一切都应该是一个对象。”
并非一切都应该是一个lambda :)自由站功能没有任何问题。
答案 3 :(得分:1)
在我看来它没用,但你可以只使用C ++ 03来实现它
void foo() {
struct {
void operator()() {}
} bar;
bar();
}
但是再一次,恕我直言,这是没用的。
答案 4 :(得分:1)
这是一个非常有限的用例。对于初学者来说,必须在封闭函数内的几个点处需要本地函数中存在的功能,这样得到的局部重构将是可读性的胜利。否则,我将内联编写功能,如果有帮助,可能会把它放在一个块中。
但与此同时,功能必须是本地的或特定的,以至于我没有动机重构(不是那样)封闭功能的外部的功能,我可能也许在某些时候将它完全重用于另一个函数。它也必须简短:否则我只是将其移出,也许将它放在一个匿名命名空间(或标题中的namespace detail
)或其他一些。交易地点以支持紧凑性并不需要太多时间(长期功能很难回顾)。
请注意,上述内容与语言无关。我不认为C ++会对此产生特别的影响。但是,如果有一个特定的C ++建议我必须就该主题给出,那就是我将使用默认的引用捕获([&]
)禁止。在没有仔细检查整个身体的情况下,无法判断该特定lambda表达式是否描述了闭包或局部函数。如果不是因为by-reference捕获([&]
,[&foo]
)允许突变即使lambda没有被标记,那也不会那么糟糕(并不是那个闭包是'可怕的')可变和按值捕获([=]
,[foo]
)可以制作不合需要的副本,甚至可以为仅移动类型尝试不可能的副本。总而言之,如果可能的话,我宁愿不捕捉任何东西(这是参数的用途!),并在需要时使用单独的捕获。这特别有问题
总结一下:
// foo is expensive to copy, but ubiquitous enough
// that capturing it rather than passing it as a parameter
// is acceptable
auto const& foo_view = foo;
auto do_quux = [&foo_view](arg_type0 arg0, arg_type1 arg1) -> quux_type
{
auto b = baz(foo_view, arg0, arg1);
b.frobnicate;
return foo_view.quux(b);
};
// use do_quux several times later