Лямбда-выражения c++: разница между "изменчивый" и захват по ссылке


В C++ вы можете объявить лямбды, например, так:

int x = 5;
auto a = [=]() mutable { ++x; std::cout << x << 'n'; };
auto b = [&]()         { ++x; std::cout << x << 'n'; };

оба позвольте мне изменить x, Так в чем же разница?

1 60

1 ответ:

что происходит

первый будет изменять только свою собственную копию x и оставьте снаружи x без изменений. Второй будет изменять за пределами x.

добавить инструкцию печати после каждой попытки:

a();
std::cout << x << "----\n";
b();
std::cout << x << '\n';

ожидается, что это для печати:

6
5
----
6
6

почему

это может помочь рассмотреть, что лямбда [...] expressions provide a concise way to create simple function objects (см. [expr.подтянутый.лямда стандарта).

у них есть [...] оператор вызова общедоступной встроенной функции [...] который объявлен как const функция-член, но только [...] если и только если лямбда-выражение parameter-declaration-clause не следует mutable (курсивный текст-цитаты из стандарта).

вы можете думать как бы

    int x = 5;
    auto a = [=]() mutable { ++x; std::cout << x << '\n'; };

==>

    int x = 5;

    class __lambda_a {
        int x;
    public:
        __lambda_a () : x($lookup-one-outer$::x) {}
        inline void operator() { ++x; std::cout << x << '\n'; }     
    } a;

и

    auto b = [&]()         { ++x; std::cout << x << '\n'; };

==>

    int x = 5;

    class __lambda_b {
        int &x;
    public:
        __lambda_b() : x($lookup-one-outer$::x) {}
        inline void operator() const { ++x; std::cout << x << '\n'; }         
        //                     ^^^^^
    } b;

Q: но если это const функция, почему я все еще могу изменить x?

A: ты только меняешься снаружи x. Собственная лямбда x - это ссылка, а операция ++x не изменяет ссылка, а ссылка на значение.

это работает, потому что в C++ константа указателя/ссылки не изменяет константу указателя/ссылки, видимого через него.