Подтвердить что ты не робот

Лямбда-захват по значению изменчивый не работает с const &?

Рассмотрим следующее:

void test( const int &value )
{
    auto testConstRefMutableCopy = [value] () mutable {
        value = 2; // compile error: Cannot assign to a variable captured by copy in a non-mutable lambda
    };

    int valueCopy = value;
    auto testCopyMutableCopy = [valueCopy] () mutable {
        valueCopy = 2; // compiles OK
    };
}

Почему первая версия является компиляционной ошибкой, когда я объявлял лямбда как измененную и захваченную value по значению (которая, как я думал, сделала ее копию)?

Протестировано с помощью clang (x86_64-apple-darwin14.3.0), откуда приходит сообщение об ошибке, и Visual С++ (vc120).

4b9b3361

Ответ 1

[C++11: 5.1.2/14]: Объект захвачен копией, если он неявно зафиксирован, а значение по умолчанию - = или , если оно явно захвачено с захватом, который не включает &. Для каждого объекта, захваченного копией, в типе закрытия объявляется неназванный нестатический элемент данных. Порядок объявления этих членов не указан. Тип такого элемента данных является типом соответствующего захваченного объекта, если объект не является ссылкой на объект или ссылочным типом иначе. [..]

Тип value внутри вашей лямбда const int, потому что он был захвачен копией из const int&.

Таким образом, хотя функция оператора лямбда-вызова не const (вы отметили lambda mutable), фактический неявный член value имеет тип const int и не может быть изменен.

Честно говоря, это кажется абсурдным; Я бы ожидал, что это правило скажет, что ссылочный тип теряет const ness, так как это копия. Присутствие или отсутствие ключевого слова mutable на самой лямбда (и, следовательно, наличие или отсутствие ключевого слова const в сгенерированной функции вызова оператора) должно быть единственным контролем доступа здесь.

В С++ 14 вы можете обойти это, взяв в качестве [value=value], который использует те же правила, что и auto, и тем самым сбрасывает const. С++ отлично, не так ли?

Ответ 2

mutable позволяет лямбда изменять копию неконстантного параметра, захваченного копией, но она не позволяет использовать параметры const.

Итак, этот код работает (и выводит inside 2 outside 1):

int a = 1;
[a]() mutable {
    a = 2; // compiles OK
    cout << "inside " << a << "\n";
}();
cout << " outside " << a << "\n";

Но если мы опустим mutable или сделаем a const int, компилятор выдаст ошибку.

В нашем случае первая лямбда дает ошибку, потому что value есть const:

void test( const int &value )

Если мы сделаем copyValue const:

const int valueCopy = value;

то такая же ошибка произойдет со второй лямбдой.