如果使用/ std:c ++ 17在MSVC2017 15.9.3中使用静态本地错误,lambda返回的值是多少?

Sam*_*ale 6 c++ visual-c++ compiler-bug c++17 visual-studio-2017

下面的示例代码从lambda函数打印值,该函数简单地递增并返回静态局部计数器变量的值.

它使用gcc和clang C++ 17进行打印0,12,3预期.但是在Visual Studio Community 2017 15.9.3中没有/std:c++17设置 - 它打印0,02,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两个v1v2,但正确打印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这里是输出,至少.

Rak*_*111 6

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那样的东西(或者使用我们无法知道的其他启发式).