Передача постоянной ссылкой в ​​списке захвата лямбда

Я создаю лямбда-функцию, которая требует доступа к множеству переменных в контексте.

const double defaultAmount = [&]{
    /*ToDo*/
}();

Я бы предпочел не использовать [=] в списке, так как мне не нужно делать много копий значений.

Меня беспокоит стабильность программы, если я использую [&], так как я не хочу, чтобы лямбда модифицировала набор захвата.

Могу ли я передать ссылку const? [const &] не работает.

Возможно, хороший компилятор оптимизирует копии значений, поэтому [=] является предпочтительным.

Ответ 1

Вы можете явно создавать и фиксировать ссылки на ссылки:

int x = 42;
const int& rx = x;
auto l = [&rx]() {
    x = 5; // error: 'x' is not captured
    rx = 5; // error: assignment of read-only reference 'rx'
};

Ответ 2

Список захвата ограничен тем, что можно захватить; в основном по значению или по ссылке (с именем или по умолчанию), указателем this и ничего.

Из cppreference;

capture-list - список с нулевым или большим количеством разделенных запятыми, необязательно начинающийся с по умолчанию-захвата. Список захвата можно передать следующим образом (см. Ниже подробное описание):

  • [a,&b], где a фиксируется по значению, а b - по ссылке.
  • [this] отображает указатель this по значению
  • [&] захватывает все автоматические переменные odr, используемые в теле лямбда по ссылке
  • [=] фиксирует все автоматические переменные odr, используемые в теле лямбда по значению
  • [] не фиксирует ничего

Вы можете создать локальный const& для всего объекта, который вы хотите захватить, и использовать его в лямбда.

#include <iostream>

using namespace std;

int main()
{
    int a = 5;
    const int& refa = a;
    const int b = [&]() -> int {
        //refa = 10; // attempts to modify this fail
        return refa;
    }();
    cout << a << " " << b << endl;
}

Захват может быть либо для всех ссылок, либо для явного списка, что требуется;

const int b = [&refa]()

Другой альтернативой является вовсе не локализовать локальные переменные. Затем вы создаете лямбду, которая принимает в качестве аргументов нужные вам переменные. Это может быть большим усилием по мере увеличения количества локальных переменных, но у вас больше контроля над тем, как лямбда принимает свои аргументы и может использовать данные.

auto lambda = [](const int& refa /*, ...*/) { */...*/ }
lambda(...);

Ответ 3

К сожалению, грамматика С++ 11 не позволяет этого, поэтому нет.

Ответ 4

Вы можете фиксировать постоянную ссылку на объект, а не на объект:

A a;
const A& ref_a = a;

const double defaultAmount = [&]{
    ref_a.smth();
}();