新的 C++11 标准支持 lambda 函数,我认为这是一个有用的特性。我知道 C 和 C++ 标准彼此不同,但我不明白为什么 C11 不支持 lambda 函数。我认为它可以有很多用处。
C11 标准的开发人员选择不包含此功能是否有原因?
2021 年更新:基于具有极简语义的 C++ 语法的 lambdas 在今年被选入 C23。随着委员会准确确定该功能将从 C++ 和其他实现中带来的其他内容,更多细节将会浮出水面。
2016 年更新:在 2016 年伦敦会议上,Apple 风格的 lambdas 再次提交给工作组,在一份新的提案文件中,该文件试图解决上一次尝试的几个失败,整理术语和解释并进入关于如何使闭包和 lambda 成为“C-like”的更多细节。
由于接收是谨慎积极的(7-0-9 是/否/弃权),看起来类似的东西很快就会进入语言。
简短的回答是 C 不包含 lambda 函数,因为尚未向 ISO C 工作组提出可接受的提议以包含 lambda 函数。
您可以在此处查看工作组讨论的一些提案的列表:http ://www.open-std.org/jtc1/sc22/wg14/www/documents
我可以在该列表中找到的任何类型的 lambda 的唯一建议是 Apple 的块(如 Yu Hao 的回答所示),在文档N1451中。该提案在N1483中进一步讨论,将其与 C++ lambdas 进行了比较,N1493和N1542是提交这些文件的会议记录。
N1451 中的提案不能被接受有几个原因,在 N1542 中给出:
看起来他们也不相信它目前展示了足够的实用性。C 标准化显然试图非常保守,并且只有一个主要的编译器实现了该功能,他们可能希望等待,看看它如何与 C++ lambda 竞争,以及是否有其他人选择它。在多个编译器提供之前,它并不是真正的“C”功能,而是“Clang”功能。
综上所述,委员会的投票显然略微倾向于该功能(6-5-4 是/否/弃权),但不足以达成必要的共识来包括它。
据我所知,另一个大的 C++11 lambdas 还没有被任何人提议包含在 C 中。如果你不问,你就得不到。
任何关于 C 中 lambda 的提议都会添加一系列关于变量生命周期和位置以及复制和分配等等的新规则。对于很多人来说,这可能开始看起来非常不像 C,随着值的移动在程序员背后或在他们的生命周期中突然发生意想不到的变化 - 避免这种事情是当今人们选择用 C 编写的一半原因。因此,还必须有一个真正符合 C 的“哲学”的提案才能被认真对待。我确信这是可以做到的,但是到目前为止,这两个大提案都是为具有非常不同的“哲学”的语言设计的,其中这种事情的障碍较少,并且不一定反映 C'
C 旨在成为一种小而简单的语言。当可以通过更简单的方式完成相同的事情时,它会故意省略高级功能。它旨在仅提供可移植编程绝对必要的基本功能。
C 没有引用,因为它们只是指针。C 没有类、继承和虚函数,因为您可以只使用结构并使用函数指针自己制作 vtable。它没有垃圾收集器,因为程序员可以自己跟踪内存分配,它没有模板,因为它们实际上只是宏。如果您需要例外,您可以使用 longjmp,而不是命名空间,您只需为名称添加前缀。
添加这些高级快捷方式中的任何一个都可能使编程更加舒适,但这是以使语言更加复杂为代价的,这一点不容小觑。这是一个滑坡,直接导致C++变得一团糟。
C 没有 lambda 函数,因为它们不是必需的。相反,您可以只使用静态函数并将上下文放入结构中。
这只是我的意见,因为我不知道委员会的想法。
一方面,Lisp 从 1958 年诞生就一直支持 lambda 表达式。C 编程语言诞生于 1972 年。所以 lambda 表达式其实比 C 有更长的历史。所以如果你问为什么 C11 不支持lambda 表达式,关于 C89 可以问同样的问题。
另一方面,lambda 表达式一直是函数式编程的东西,并逐渐被命令式编程语言所吸收。一些“高级”语言(例如,Java 8 之前的 Java)还不支持它。
最后,C 和 C++ 总是互相学习,所以也许它会出现在下一个 C 标准中。现在,您可以看看Blocks,这是 Apple 添加的非标准扩展。这是来自维基百科的示例代码:
#include <stdio.h>
#include <Block.h>
typedef int (^IntBlock)();
IntBlock MakeCounter(int start, int increment) {
__block int i = start;
return Block_copy( ^ {
int ret = i;
i += increment;
return ret;
});
}
int main(void) {
IntBlock mycounter = MakeCounter(5, 2);
printf("First call: %d\n", mycounter());
printf("Second call: %d\n", mycounter());
printf("Third call: %d\n", mycounter());
/* because it was copied, it must also be released */
Block_release(mycounter);
return 0;
}
/* Output:
First call: 5
Second call: 7
Third call: 9
*/