Возможно ли доступ (только для чтения) к переменным, захваченным лямбдой?

Можно ли получить доступ (только для чтения) переменные, захваченные лямбдой?

Это не работает:

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 прямо здесь.