未计算上下文中的 lambda (C++20 前)
lambdas in unevaluated contexts (Until C++20)
我目前正在阅读 P0315R1 论文,其中讨论了 Lambdas in unevaluated contexts
文档中有一个声明解释了为什么 lambda 不能出现在未计算的上下文中(当然只有在 C++20 之前),如下所示:
Lambdas are a very powerful language feature, especially when it comes
to using higher-order algorithms with custom predicates or expressing
small, disposable pieces of code. Yet, they suffer from one important
limitation which cripples their usefulness for creative use cases;
they can’t appear in unevaluated contexts. This restriction was
originally designed to prevent lambdas from appearing in signatures,
which would have opened a can of worm for mangling because lambdas are
required to have unique types.
有人可以举例说明这个说法吗?
一些背景知识:链接器不理解函数重载——它们只理解 C 语言中的函数名称。这就是为什么 C++ 编译器会破坏您的函数名称。 void foo(int)
变为 _Z3fooi
。损坏的名称对所有参数的类型进行编码。如果您的函数是由模板实例化产生的,那么所有模板参数也会被编码。如果它们本身是模板 类,它们的模板参数将被编码,递归地依此类推,直到达到像 int 或函数指针这样的原始类型。
Lambda 使这具有挑战性,因为每个 lambda 都需要具有不同的类型。这对于函数中定义的 lambda 来说还算不错:
auto foo() { return [](){}; }
auto bar() { return [](){}; }
foo
和bar
return不同的类型。如果您随后将它们传递给另一个函数模板,则该模板的名称将被破坏,就像使用 foo::__lambda1
或类似的东西一样。
让 lambda 出现在 decltype
中会破坏这个机制。
void bar(decltype([](){}));
void bar(decltype([](){})) {}
这是原型和定义吗?还是这两个不同的 bar
重载?如何跨翻译单元识别它们(如何破坏名称)?
直到现在,C++ 甚至禁止问这个问题。您链接的论文给出了答案:这样的事情不能有联系。甚至不要试图破坏它们。
如果我们在头文件的函数签名中有一个 decltype 为 lambda 的内联函数。编译器会在包含该函数的每个翻译单元中为该函数生成一个唯一的错位名称。
所以最后链接器无法合并 "same" 函数的这些多个定义,因为损坏的名称不同。
我目前正在阅读 P0315R1 论文,其中讨论了 Lambdas in unevaluated contexts
文档中有一个声明解释了为什么 lambda 不能出现在未计算的上下文中(当然只有在 C++20 之前),如下所示:
Lambdas are a very powerful language feature, especially when it comes to using higher-order algorithms with custom predicates or expressing small, disposable pieces of code. Yet, they suffer from one important limitation which cripples their usefulness for creative use cases; they can’t appear in unevaluated contexts. This restriction was originally designed to prevent lambdas from appearing in signatures, which would have opened a can of worm for mangling because lambdas are required to have unique types.
有人可以举例说明这个说法吗?
一些背景知识:链接器不理解函数重载——它们只理解 C 语言中的函数名称。这就是为什么 C++ 编译器会破坏您的函数名称。 void foo(int)
变为 _Z3fooi
。损坏的名称对所有参数的类型进行编码。如果您的函数是由模板实例化产生的,那么所有模板参数也会被编码。如果它们本身是模板 类,它们的模板参数将被编码,递归地依此类推,直到达到像 int 或函数指针这样的原始类型。
Lambda 使这具有挑战性,因为每个 lambda 都需要具有不同的类型。这对于函数中定义的 lambda 来说还算不错:
auto foo() { return [](){}; }
auto bar() { return [](){}; }
foo
和bar
return不同的类型。如果您随后将它们传递给另一个函数模板,则该模板的名称将被破坏,就像使用 foo::__lambda1
或类似的东西一样。
让 lambda 出现在 decltype
中会破坏这个机制。
void bar(decltype([](){}));
void bar(decltype([](){})) {}
这是原型和定义吗?还是这两个不同的 bar
重载?如何跨翻译单元识别它们(如何破坏名称)?
直到现在,C++ 甚至禁止问这个问题。您链接的论文给出了答案:这样的事情不能有联系。甚至不要试图破坏它们。
如果我们在头文件的函数签名中有一个 decltype 为 lambda 的内联函数。编译器会在包含该函数的每个翻译单元中为该函数生成一个唯一的错位名称。
所以最后链接器无法合并 "same" 函数的这些多个定义,因为损坏的名称不同。