Sam*_*ale 6 c++ visual-c++ compiler-bug c++17 visual-studio-2017
下面的示例代码从lambda函数打印值,该函数简单地递增并返回静态局部计数器变量的值.
它使用gcc和clang C++ 17进行打印0,1和2,3预期.但是在Visual Studio Community 2017 15.9.3中没有/std:c++17设置 - 它打印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;
}
Run Code Online (Sandbox Code Playgroud)
奇怪的输出(在x86调试版本中)
0,0
2,3
Run Code Online (Sandbox Code Playgroud)
它看起来像编译器错误(所以我们提交了报告):https://developercommunity.visualstudio.com/content/problem/347419/unexpected-return-from-lambda-with-static-local-va.html
以何种方式是产生程序错误,使得它错误地打印0两个v1和v2,但正确打印2, 3之后呢?任何有根据的猜测编译器错误是什么?
作为一种解决方法,我使用了捕获:
auto f = [i = 0]() mutable {
return i++;
};
Run Code Online (Sandbox Code Playgroud)
更新 - 作为旁注,上面示例的输出在x86发布版本中再次不同:
0,1
3,2
Run Code Online (Sandbox Code Playgroud)
没有与MSVC,这里又存在问题std::cout的<<经营者没有测序左到右,尽管/std:c++17被设置,这也是我推测在结果3,2这里是输出,至少.
MSVC干净地编译以下内容:
constexpr int foo() {
static int i = 0;
return i++;
}
static_assert(foo() == foo()); // oh no
Run Code Online (Sandbox Code Playgroud)
这不符合标准.
所以,会发生的事情是,自从C++ 17以来,lambdas就是隐含的,constexpr如果可以的话.MSVC错误地判定lambda是constexpr,并因此折叠f()成一个常数v2(它来自v1).当你直接输出它时它不会这样做,因为它显然不会急切地评估constexpr像gcc那样的东西(或者使用我们无法知道的其他启发式).