Должны ли мы захватывать по константной ссылке в лямбде? - PullRequest
0 голосов
/ 10 июня 2018

Я читал Лямбда-захват как постоянную ссылку?
Это интересная функция, и иногда я также хочу, чтобы эта функция существовала, особенно когда у меня есть огромные данные, к которым мне нужно получить доступвнутри лямбда-функции.

Мои последующие вопросы -

  • Должны ли мы фиксировать константную ссылку в лямбда-выражении?Если да, как оно должно себя вести?
    (Правка - меня также интересует поведение времени жизни захваченной переменной.)
  • Есть ли возможный недостаток, введя его вграмматика C ++? (я не могу думать ни о чем)

Давайте предположим, что можем.
Мы предполагаем [const &] в качестве синтаксиса для захвата.

int x = 10;
auto lambda = [const & x](){ std::cout << x << std::endl; }; 
lambda(); // prints 10, great, as expected

x = 11;
lambda(); // should it print 11 or 10 ?

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

template<typename Func>
void higher_order_function(int & x, Func f)
{
    f(); // should print 11
    x = 12;
    f(); // should print 12
}

void foo()
{
    int x = 10;
    auto c = [const & x] () { std::cout << x << std::endl; };

    c(); // should print 10
    x = 11;
    c(); // should print 11
    higher_order_function(x, c);

    auto d = [const & x] () { x = 13; }; // Compiler ERROR: Tried to assign to const qualified type 'const int &'!
} 

Ответы [ 3 ]

0 голосов
/ 10 июня 2018
lambda(); // should it print 11 or 10 ?

Я не понимаю, почему он должен печатать 10. Рассмотрим lambda как экземпляр какого-то анонимного класса.Делая его нормальным классом, он должен выглядеть следующим образом:

class Lambda {
   public:
      Lambda(const int & i) : i_(i) { }
      void operator()() { std::cout << i_ << std::endl; }
   private:
      const int & i_;
 };

int x = 10;
Lambda lambda(x);
lambda(); // prints 10, great, as expected

x = 11;
lambda(); // should it print 11 or 10 ?

Смысл константной ссылки здесь заключается только в том, что вы не можете изменять x через i_ переменную ссылки на член.


Сценарий simlpler:

int x = 10;
const int & crx = x;
x++;
std::cout << crx << std::endl; // prints 11
0 голосов
/ 10 июня 2018

Мне самому было интересно об этом.
Так как operator () по умолчанию является const, я бы предположил, что допустимо использование ссылок на const.

С текущими стандартами (C +)+17), самое близкое, что я получил к этому поведению:

auto c = [ &x = std::as_const(x) ] () { std::cout << x << std::endl; };

Обходной путь в C ++ 11 / C ++ 14 будет (спасибо Дэниелу за предложение):

auto const & crx = x;
auto c = [ &crx ] () { std::cout << crx << std::endl; };
0 голосов
/ 10 июня 2018

Может быть, не совсем то, что вы ищете, но ... я полагаю, вы можете пройти через функцию, которая получает то же значение по константной ссылке.

Что-то следующее

template <typename T>
auto make_capture_const (T const & x)
 { return [&x](){ std::cout << x << std::endl; }; }

// ...

int x { 42 };

auto l = make_capture_const(x);

l();

Если вы попытаетесь изменить x внутри лямбды

std::cout << x++ << std::endl;

, вы должны получить сообщение об ошибке.

Как вы можете видеть, из этого решения вы получаете, что x может 'Он не может быть изменен внутри лямбды, но на лямбду влияют изменения значений вне

   int x { 42 };

   auto l = make_capture_const(x);

   l();  // print 42

   x = 43;

   l();  // print 43

ИМХО, гипотетический синтаксис захвата [const &] должен работать таким же образом.Но я понимаю, что это очень сомнительно.

...