Lambda capture by value mutable не работает с 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 C++ (vc120).

569   2  

2 ответов:

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

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

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

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

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

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

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

int a = 1;
[a]() mutable {
    a = 2; // compiles OK
    cout << "inside " << a << "\n";
}();
cout << " outside " << a << "\n";
Но если мы опустим mutable или сделаем const int, компилятор выдаст ошибку.

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

void test( const int &value )

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

const int valueCopy = value;

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

Comments

    Ничего не найдено.