【发布时间】:2019-05-01 00:36:03
【问题描述】:
在直观的层面上,不需要携带任何状态(通过引用或其他方式)的 lambda 应该可以干净地转换为裸函数指针是有道理的。然而,我最近惊讶地发现 GCC、Clang 和 MSVC 中出现以下错误:
int main(int, char *[]) {
void (*fp)() = []{}; // OK
//fp = [=]{}; // XXX - no user defined conversion operator available
//fp = [&]{}; // XXX - same ...
}
C++17 规范(或至少 visible public draft version N4713)在第 8.4.5.1 节的第 7 项中引用了 [expr.prim.lambda.closure] 对带有和不带有捕获的 lambda:
非泛型 lambda 表达式的闭包类型没有 lambda 捕获,其约束(如果有)得到满足,具有一个转换函数指向具有 C++ 语言链接 (10.5) 的函数的指针与闭包类型的函数调用运算符相同的参数和返回类型。 ...
但是,查看正式语法,您可以在第 8.4.5 节中看到以下内容[expr.prim.lambda]:
- lambda 表达式:
- lambda-introducer 复合语句
- ...
- lambda-introducer:
- [lambda-captureopt]
- ...
并在 § 8.4.5.2 [expr.prim.lambda.capture]:
- lambda 捕获:
- 默认捕获
- 捕获列表
- 默认捕获,捕获列表
- 默认捕获:
- &
- =
因此,令我沮丧的是,所有编译器实际上都在遵守法律条文......
为什么语言将捕获的存在定义为声明中的一种狭义语法区别,而不是基于主体是否包含对任何非静态/捕获状态的引用?
【问题讨论】:
-
你假设
[=]和[&]没有捕获fp他们所做的。 -
@0x499602D2 为什么
fp没有在体内使用? -
我认为在当前标准文本中指定的方式正是最容易写下来的方式。我可以反过来问你为什么要使用
[=],而你显然不想捕捉任何东西。 -
@Brian 这显然是一个人为的最小示例。我的真实用例涉及一个返回 lambda 的可变参数完美转发函数,该函数在被包装在类型擦除类中后在其他地方检查是否有状态。解决方法是在内部测试 sizeof...(args) 并产生两个几乎相同的 lambda 主体之一,但这是一个丑陋的模式。
标签: c++ c++11 lambda language-lawyer function-pointers