gpt4 book ai didi

c++ - 为什么这些 lambda 捕获的值有不同的类型?

转载 作者:行者123 更新时间:2023-12-05 03:27:32 25 4
gpt4 key购买 nike

两个 int 变量,一个是引用,当被 lambda 捕获时,在 MSVC 的 c++20 中类型不同。为什么?

Scott 在编译时确定类型的技术在 c++14 和 17 中产生了预期的结果,但在 c++20 中却没有。然而,这种奇怪的差异似乎也出现在早期版本的其他编译中。

具体来说,两个整数,一个是引用,当被值或引用捕获时会产生不同的类型。 intint &。然而,较早的版本会产生预期的类型。当按值捕获时,两者都被键入 int。当通过引用捕获时,两者都是 int &

// Scott Meyer's compile time Type Deduction technique
template<typename T>
class TD;

int main()
{
int i{ 1 };
int& ri = i;

[i, ri]() mutable {
TD<decltype(i)> WhatAmI1; // c++14, c++17 TD<int>, c++20 TD<int>
TD<decltype(ri)> WhatAmI2; // c++14, c++17 TD<int>, c++20 TD<int &>
}();

[&i, &ri]() mutable {
TD<decltype(i)> WhatAmI3; // c++14, c++17 TD<int&>, c++20 TD<int>
TD<decltype(ri)> WhatAmI4; // c++14, c++17 TD<int&>, c++20 TD<int &>
}();
}

进一步探索这一点,生成的代码符合预期,并且对于捕获的值和捕获的引用都是相同的。

int main()
{
int i{ 1 };
int& ri = i;

[i, ri]() mutable {
i += 2;
ri += 3;
}();

[&i, &ri]() {
i += 2;
ri += 3;
}();
}

[i, ri]() mutable {
i += 2;
00007FF7F506187F 48 8B 85 E0 00 00 00 mov rax,qword ptr [this]
00007FF7F5061886 8B 00 mov eax,dword ptr [rax]
00007FF7F5061888 83 C0 02 add eax,2
00007FF7F506188B 48 8B 8D E0 00 00 00 mov rcx,qword ptr [this]
00007FF7F5061892 89 01 mov dword ptr [rcx],eax
ri += 3;
00007FF7F5061894 48 8B 85 E0 00 00 00 mov rax,qword ptr [this]
00007FF7F506189B 8B 40 04 mov eax,dword ptr [rax+4]
00007FF7F506189E 83 C0 03 add eax,3
00007FF7F50618A1 48 8B 8D E0 00 00 00 mov rcx,qword ptr [this]
00007FF7F50618A8 89 41 04 mov dword ptr [rcx+4],eax



[&i, &ri]() {
i += 2;
00007FF7F506190F 48 8B 85 E0 00 00 00 mov rax,qword ptr [this]
00007FF7F5061916 48 8B 00 mov rax,qword ptr [rax]
00007FF7F5061919 8B 00 mov eax,dword ptr [rax]
00007FF7F506191B 83 C0 02 add eax,2
00007FF7F506191E 48 8B 8D E0 00 00 00 mov rcx,qword ptr [this]
00007FF7F5061925 48 8B 09 mov rcx,qword ptr [rcx]
00007FF7F5061928 89 01 mov dword ptr [rcx],eax
ri += 3;
00007FF7F506192A 48 8B 85 E0 00 00 00 mov rax,qword ptr [this]
00007FF7F5061931 48 8B 40 08 mov rax,qword ptr [rax+8]
00007FF7F5061935 8B 00 mov eax,dword ptr [rax]
00007FF7F5061937 83 C0 03 add eax,3
00007FF7F506193A 48 8B 8D E0 00 00 00 mov rcx,qword ptr [this]
00007FF7F5061941 48 8B 49 08 mov rcx,qword ptr [rcx+8]
00007FF7F5061945 89 01 mov dword ptr [rcx],eax
}();

编译器资源管理器链接 https://godbolt.org/z/oe9KPcWWv

最佳答案

Clang、GCC 和 MSVC 在 C++20 模式下的行为对于所有支持 lambda 的标准版本都是正确的。 decltype(i)decltype(ri) 产生命名变量的类型。它没有被重写为引用闭包对象的成员,就像 decltype((ri)) 的情况一样。 (参见例如 C++17 草案 N4659 中的 [expr.prim.lambda.capture]/14 专门处理此问题)

显然,MSVC 在 C++20 之前的标准模式默认行为在 lambda 的处理方式上是不一致的。根据documentation必须给出标志 /Zc:lambda 来处理符合标准的 lambda。使用此选项,对于 C++17 和 C++14 模式,MSVC 也会产生与 C++20 模式相同的结果。

参见示例 this bug report它作为非错误关闭,并附有使用此标志的说明。另请注意,它似乎并未包含在 /permissive- 中。

关于c++ - 为什么这些 lambda 捕获的值有不同的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71460427/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com