我目前正在阅读P0315R1文章,该文章讨论了未评估上下文中的Lambdas
文档中有一条语句说明了为什么lambda不能在未评估的上下文中出现(当然只有在C ++ 20之前),如下所示:
Lambda是一项非常强大的语言功能,尤其是当它出现时 使用带有自定义谓词或表达式的高阶算法 小的一次性代码段。然而,他们患有一个重要的疾病 限制削弱了其对创造性用例的有用性; 它们不能出现在未经评估的环境中。 此限制是 最初旨在防止lambda出现在签名中, 这会打开一罐蠕虫进行破坏,因为lambda是 必须具有唯一的类型。
有人可以举例说明一下这个说法吗?
答案 0 :(得分:5)
一些背景知识:链接器不理解函数重载-它们仅像C语言一样理解函数名称。这就是C ++编译器修改您的函数名称的原因。 void foo(int)
成为_Z3fooi
。整齐的名称会编码所有参数的类型。如果您的函数是由模板实例化产生的,则所有模板参数也会被编码。如果它们本身是模板类,则将对它们的模板参数进行编码,然后进行递归编码,直到达到基本类型(如int或函数指针)为止。
Lambda使这一挑战变得棘手,因为每个Lambda都必须具有不同的类型。对于在函数中定义的lambda来说,还算不错:
auto foo() { return [](){}; }
auto bar() { return [](){}; }
foo
和bar
返回不同的类型。然后,如果将它们传递给另一个功能模板,则该模板的名称将像使用foo::__lambda1
或类似的名称那样进行修饰。
在decltype
中出现lambda会破坏这种机制。
void bar(decltype([](){}));
void bar(decltype([](){})) {}
这是原型还是定义?还是bar
的这两种不同的重载?如何跨翻译单位识别它们(如何处理名称)?
直到现在,C ++甚至禁止问这个问题。您链接的论文给出了一个答案:诸如此类的事情不能相互关联。甚至不要试图破坏它们。
答案 1 :(得分:0)
如果我们在头文件的函数签名中有一个内联函数,其内函数具有 lambda的decltype 。编译器会在包含该函数的每个翻译单元中为此函数生成一个唯一的错误名称。
所以最后,链接器无法合并“相同”功能的这些多个定义,因为名称混乱。