В С++ вы можете объявить lambdas, например, следующим образом:
int x = 5;
auto a = [=]() mutable { ++x; std::cout << x << '\n'; };
auto b = [&]() { ++x; std::cout << x << '\n'; };
Оба позволяют мне изменить x
, так в чем же разница?
В С++ вы можете объявить lambdas, например, следующим образом:
int x = 5;
auto a = [=]() mutable { ++x; std::cout << x << '\n'; };
auto b = [&]() { ++x; std::cout << x << '\n'; };
Оба позволяют мне изменить x
, так в чем же разница?
Первый изменит только свою собственную копию x
и оставит внешний x
неизменным.
Второй будет изменять внешний x
.
Добавьте инструкцию печати после каждого из них:
a();
std::cout << x << "----\n";
b();
std::cout << x << '\n';
Ожидается печать:
6
5
----
6
6
Это может помочь рассмотреть эту lambda [...] expressions provide a concise way to create simple function objects
(см. [expr.prim.lambda] стандарта).
У них есть [...] открытый оператор вызова встроенной функции [...], который объявлен как функция-член 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
. Свойство lambda x
является ссылкой, а операция ++x
не изменяет ссылку, а ссылается на значение.
Это работает, потому что в С++ константа указателя/ссылки не изменяет консистенцию указателя/ссылки, видимого через него.