Возможно ли доступ (только для чтения) к переменным, захваченным лямбдой?
Можно ли получить доступ (только для чтения) переменные, захваченные лямбдой?
Это не работает:
std::function<double (const double)> plus (const double a) {
return [a] (const double b) -> double {
return a+b;
};
}
auto plus5 = plus(5);
cout << plus5.a << endl;
Ответы
Ответ 1
auto plus( double a ) {
using R = struct {
double a;
double operator()(double b)const{return b+a;}
};
return R{std::move(a)};
}
живой пример.
Обратите внимание, что std::function
не является лямбдой, а лямбда не является std::function
. Они работают друг с другом, но использование одного термина для обозначения другого противоположно полезному.
Ответ 2
Это не то, как следует использовать лямбда.
Интерфейс лямбда является его сигнатурой функции. Его захваты должны рассматриваться как детали реализации и не быть видимыми пользователю.
Если вам нужен явный доступ к захватам, напишите свой собственный объект функции и соответствующим образом разместите соответствующие элементы данных:
struct MyPlus {
double a;
MyPlus(double x) : a(x) {}
double operator()(const double b)
{
return a+b;
}
};
auto plus5 = MyPlus(5);
std::cout << plus5.a;
Ответ 3
"Определенно не после сохранения его в std-функции. Без этого я мог бы сделать это с ужасным (но законным) взломом на С++ 17. Но я был бы ужасным человеком, чтобы рассказать вам, как, используй это." - Якк
Хорошо, пусть облегчит карму Якка; здесь доказательство концепции решения С++ 14, которое вы определенно не хотите выпускать в дикой природе:
auto magic = [a, b](auto &&... args) mutable -> decltype(auto) {
return makeOverload(
// Capture access boilerplate
[&](cap_<0>) -> auto& { return a; },
[&](cap_<1>) -> auto& { return b; },
// Actual function
[&](int p) {
return "[" + std::to_string(a) + ", " + b + "](" + std::to_string(p) + ")";
}
)(std::forward<decltype(args)>(args)...);
};
makeOverload
принимает любое число функторов и смешивает их в один. Я заимствовал идею из этого сообщения в блоге, с помощью раздела комментариев, чтобы он действительно работал.
Полученный функтор используется для отправки тегов между тегами cap<N>
и фактическими параметрами функции. Таким образом, вызов magic(cap<0>)
заставляет его выплевывать соответствующую захваченную переменную, то есть a
. Фактическое поведение функции, конечно, все еще доступно с обычным вызовом magic(123)
.
В качестве бонуса внешняя лямбда mutable
, а получатели захвата возвращаются по ссылке: у вас действительно есть доступ на чтение и запись к захваченным переменным!
Вы можете наблюдать и взаимодействовать с этим существом в его естественной среде обитания на Coliru прямо здесь.