Почему "изменчивый" атрибут лямбда-функции, а не тип захвата?
Почему С++ 11 требует от нас написать:
[a,b]() mutable { a=7; } // b is needlessly mutable, potential source of bugs
Вместо:
[mutable a,b]() { a=7; } // no problems here
Является ли это надзором, который считается недостаточно важным или существует конкретная техническая причина?
Ответы
Ответ 1
Есть упоминание о вашем предложении в n2651:
Синтаксис лямбда-выражений может быть расширен, чтобы разрешить объявление следует ли объявлять закрывающие элементы изменчивыми или нет.
Этот подход может запутать программистов, поскольку изменчивость не является свойства объекта замыкания, а скорее переменные, хранящиеся в закрытие.
Я не знаю, является ли это единственной причиной, но похоже, что это было рассмотрено.
Однако в предложении Herb Sutter он предлагает избавиться от mutable
и не делать копии захвата неявно const
, чтобы мы могли видеть изменения снова.
Ответ 2
Вероятно, надзор (так же, как rvalue refs не может быть использован) рода и артефакт того, как lambdas концептуально реализованы.
int a;
int* b;
float c;
auto lambda1 = [&a, b, c](int d) mutable -> void {};
class lambda1 {
public:
void operator()(int d) {}
private:
int& a_;
int* b_;
float c_;
};
auto lambda2 = [&a, b, c](int d) -> void {};
class lambda2 {
public:
void operator()(int d) const {}
private:
int& a_;
int* b_;
float c_;
};
Ответ 3
Ключевое слово mutable
применяется к объекту, сгенерированному выражением лямбда, а не к индивидуально захваченным элементам, так что он может быть реализован компилятором с использованием модификатора const
по методу operator()
, как описано в разделе 5.1. 2, параграф 5 стандарта.
Этот оператор вызова функции объявляется const (9.3.1) тогда и только тогда, когда условие lambdaexpressions-declaration-statement не сопровождается изменяемые.
В вашем примере класс, сгенерированный выражением лямбда, может выглядеть так:
class lambda
{
int a, b;
public:
lambda( int a, int b ) : a( a ), b( b ) {}
void operator()() // non-const due to mutable keyword
{
a = 7;
}
};
Ответ 4
Ключевое слово mutable
не используется, как правило, используется ключевое слово mutable
: в данном случае оно означает противоположность const
и применяется к константе оператора вызова функции, неявный функциональный объект, Однако было преднамеренно, что оператор вызова функции объекта неявной функции по умолчанию const
, тогда как обычные функции-члены не являются const
( "mutable" ), но по умолчанию. Введение лямбда-функций предшествовало использованию контекстных ключевых слов (override
и final
), а ключевое слово mutable
выглядело лучше, чем not const
.