Можно ли захватить константной ссылкой в лямбда-выражении?
Я хочу, чтобы назначение, отмеченное ниже, не сработало, например:
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string strings[] =
{
"hello",
"world"
};
static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);
string best_string = "foo";
for_each( &strings[0], &strings[num_strings], [&best_string](const string& s)
{
best_string = s; // this should fail
}
);
return 0;
}
Обновление: поскольку это старый вопрос, было бы неплохо обновить его, если в C ++ 14 есть средства, помогающие с этим. Позволяют ли расширения в C ++ 14 захватывать неконстантный объект по константной ссылке? ( Август 2015 г. )
[&, &best_string](string const s) { ...}
?Ответы:
const
отсутствует в грамматике для захватов с n3092:В тексте упоминается только «захват за копией» и «захват по ссылке», и не упоминается никакой константности.
Для меня это похоже на недосмотр, но я не очень внимательно следил за процессом стандартизации.
источник
const
. Или, более правильно, если бы переменная захвата былаconst
, компилятор принудительно установил бы правильное поведение на программиста. Было бы хорошо, если бы синтаксис поддерживал[&mutableVar, const &constVar]
.a
какconst
, объявитеconst auto &b = a;
передb
[&foo = this->foo]
внутриconst
функции выдает ошибку, утверждающую, что сам захват отбрасывает квалификаторы. Это может быть ошибкой в GCC 5.1, хотя, я полагаю.В C ++ 14используя
static_cast
/const_cast
:DEMO
В C ++ 17используя
std::as_const
:ДЕМО 2
источник
const_cast
может безоговорочно изменить изменчивый объект на постоянный объект (когда его просят привести кconst
), таким образом, для добавления ограничений, которые я предпочитаюstatic_cast
static_cast
для сравнения может молча создать временное хранилище, если вы не совсем правильно поняли тип&basic_string = std::as_const(best_string)
должен решить все проблемыconst& best_string
.Я думаю, что часть захвата не должна указывать
const
, так как захват означает, что ей нужен только способ доступа к переменной внешней области видимости.Спецификатор лучше указывать во внешней области видимости.
Лямбда-функция является константной (не может изменить значение в своей области видимости), поэтому при захвате переменной по значению переменная не может быть изменена, но ссылка не находится в области действия лямбда-выражения.
источник
better_string
внутри содержащей области, то это решение не будет работать. Вариант использования для захвата как const-ref - это когда переменная должна быть изменяемой в содержащей области, но не в лямбда-выражении.const string &c_better_string = better_string;
и счастливо передать ее[&c_better_string]
Я предполагаю, что если вы не используете переменную в качестве параметра функтора, вам следует использовать уровень доступа текущей функции. Если вы думаете, что не должны, то отделяйте свою лямбду от этой функции, она не является частью этого.
В любом случае, вы можете легко добиться того же, чего хотите, используя вместо этого другую ссылку на const:
Но это то же самое, что предположить, что ваша лямбда должна быть изолирована от текущей функции, что делает ее не лямбда.
источник
best_string
только. Кроме того, GCC 4.5 «успешно отклоняет» код, как предполагалось.Я думаю, у вас есть три разных варианта:
используя копию
Интересная часть о лямбдах с захватами копий заключается в том, что они на самом деле только для чтения и, следовательно, делают именно то, что вам нужно.
используя std :: bind
std::bind
уменьшает арность функции. Однако обратите внимание, что это может / приведет к косвенному вызову функции через указатель функции.источник
Есть более короткий путь.
Обратите внимание, что перед "best_string" нет амперсанда.
Это будет тип "const std :: reference_wrapper << T >>".
http://coliru.stacked-crooked.com/a/0e54d6f9441e6867
источник
Используйте clang или подождите, пока ошибка gcc не будет устранена: ошибка 70385: лямбда-захват по ссылке на константную ссылку завершается неудачей [ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]
источник
Использование const просто приведет к тому, что алгоритм ampersand установит строку в исходное значение. Другими словами, лямбда не будет определять себя как параметр функции, хотя окружающая область будет иметь дополнительную переменную ... Без ее определения тем не менее, она не будет определять строку как типичную [&, & best_string] (string const s). Поэтому , скорее всего, лучше, если мы просто оставим ее при этом, пытаясь захватить ссылку.
источник