Как значение, возвращаемое лямбда-выражением при использовании статической локальной ошибки в MSVC2017 15.9.3 с / std: c ++ 17? - PullRequest
0 голосов
/ 07 декабря 2018

Приведенный ниже пример кода печатает значения из лямбда-функции, которая просто увеличивает и возвращает значение статической переменной локального счетчика.

Она печатает 0,1 и 2,3, как ожидается, с помощью gcc и clang сC ++ 17.Но не в 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;
}

Странный вывод (в отладочных сборках x86)

0,0
2,3

Похоже на ошибку компилятора (поэтому мы подали отчет): 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++;
};

UPDATE - в качестве примечания, вывод из примера выше снова отличаетсяв сборках выпуска x86:

0,1
3,2

Существует еще одна существующая проблема с MSVC, когда оператор std::cout << не упорядочен слева направо, несмотря на установленную /std:c++17, что я хотел быпредположить, что здесь выводится 3,2, по крайней мере.

1 Ответ

0 голосов
/ 07 декабря 2018

MSVC безошибочно компилирует следующее:

constexpr int foo() {
    static int i = 0;
    return i++;
}
static_assert(foo() == foo()); // oh no

То есть не не соответствует стандартам.

Итак, что происходит с C ++ 17, лямбдынеявно constexpr, если они могут быть.MSVC ошибочно решает, что лямбда равна constexpr, и поэтому складывает f() в постоянную для v2 (полученную из v1).Он не делает этого, когда вы выводите его напрямую, потому что он явно не жадно оценивает constexpr такие вещи, как делает gcc (или использует другую эвристику, о которой мы не можем знать).

...