lambda 如何在 MSVC2017 15.9.3 和 /std:c++17 中使用静态局部错误返回值?
How is value returned by lambda using a static local wrong in MSVC2017 15.9.3 with /std:c++17?
下面的示例代码打印来自 lambda 函数的值,该函数简单地递增 returns 静态局部计数器变量的值。
它按预期使用 gcc 打印 0,1
和 2,3
,使用 C++17 打印 clang。但在设置了 /std:c++17
的 Visual Studio Community 2017 15.9.3 中不存在 - 它会打印 0,0
和 2,3
。
#include <iostream>
int main() {
auto f = [] {
static int i = 0;
return i++;
};
const int v1 = f(); // Expect v1 = 0
const int v2 = f(); // Expect v2 = 1
// Prints the wrong values (MSVC 15.9.3 with /std:c++17)
std::cout << v1 << "," << v2 << std::endl; // Expect "0,1", prints "0,0"
// Prints the right values (or ought to with C++17 sequencing, anyway)
std::cout << f() << "," << f() << std::endl; // Expect "2,3", prints "2,3"
return 0;
}
奇怪的输出(在 x86 调试版本中)
0,0
2,3
它看起来像一个编译器错误(所以我们提交了报告):https://developercommunity.visualstudio.com/content/problem/347419/unexpected-return-from-lambda-with-static-local-va.html
生成的程序在哪些方面出错,以至于它错误地为 v1
和 v2
打印了 0
,但之后正确打印了 2, 3
?关于编译器错误是什么的任何有根据的猜测?
作为变通方法,我改为使用捕获:
auto f = [i = 0]() mutable {
return i++;
};
更新 - 作为旁注,上述示例的输出在 x86 发布版本中再次不同:
0,1
3,2
MSVC 还存在另一个问题,尽管设置了 /std:c++17
,但 std::cout
的 <<
运算符未按从左到右的顺序排列,我推测这会导致3,2
至少在这里输出。
MSVC 干净地编译了以下内容:
constexpr int foo() {
static int i = 0;
return i++;
}
static_assert(foo() == foo()); // oh no
即不标准。
所以,从 C++17 开始,lambda 表达式隐式 constexpr
如果可以的话。 MSVC 错误地决定 lambda 是 constexpr
,因此将 f()
折叠成 v2
的常量(它从 v1
获得)。当你直接输出它时它不会这样做,因为它显然不会像 gcc 那样急切地评估 constexpr
东西(或使用我们不知道的其他一些启发式)。
下面的示例代码打印来自 lambda 函数的值,该函数简单地递增 returns 静态局部计数器变量的值。
它按预期使用 gcc 打印 0,1
和 2,3
,使用 C++17 打印 clang。但在设置了 /std:c++17
的 Visual Studio Community 2017 15.9.3 中不存在 - 它会打印 0,0
和 2,3
。
#include <iostream>
int main() {
auto f = [] {
static int i = 0;
return i++;
};
const int v1 = f(); // Expect v1 = 0
const int v2 = f(); // Expect v2 = 1
// Prints the wrong values (MSVC 15.9.3 with /std:c++17)
std::cout << v1 << "," << v2 << std::endl; // Expect "0,1", prints "0,0"
// Prints the right values (or ought to with C++17 sequencing, anyway)
std::cout << f() << "," << f() << std::endl; // Expect "2,3", prints "2,3"
return 0;
}
奇怪的输出(在 x86 调试版本中)
0,0
2,3
它看起来像一个编译器错误(所以我们提交了报告):https://developercommunity.visualstudio.com/content/problem/347419/unexpected-return-from-lambda-with-static-local-va.html
生成的程序在哪些方面出错,以至于它错误地为 v1
和 v2
打印了 0
,但之后正确打印了 2, 3
?关于编译器错误是什么的任何有根据的猜测?
作为变通方法,我改为使用捕获:
auto f = [i = 0]() mutable {
return i++;
};
更新 - 作为旁注,上述示例的输出在 x86 发布版本中再次不同:
0,1
3,2
MSVC 还存在另一个问题,尽管设置了 /std:c++17
,但 std::cout
的 <<
运算符未按从左到右的顺序排列,我推测这会导致3,2
至少在这里输出。
MSVC 干净地编译了以下内容:
constexpr int foo() {
static int i = 0;
return i++;
}
static_assert(foo() == foo()); // oh no
即不标准。
所以,从 C++17 开始,lambda 表达式隐式 constexpr
如果可以的话。 MSVC 错误地决定 lambda 是 constexpr
,因此将 f()
折叠成 v2
的常量(它从 v1
获得)。当你直接输出它时它不会这样做,因为它显然不会像 gcc 那样急切地评估 constexpr
东西(或使用我们不知道的其他一些启发式)。