Подтвердить что ты не робот

Почему "изменчивый" атрибут лямбда-функции, а не тип захвата?

Почему С++ 11 требует от нас написать:

[a,b]() mutable { a=7; } // b is needlessly mutable, potential source of bugs

Вместо:

[mutable a,b]() { a=7; } // no problems here

Является ли это надзором, который считается недостаточно важным или существует конкретная техническая причина?

4b9b3361

Ответ 1

Есть упоминание о вашем предложении в n2651:

Синтаксис лямбда-выражений может быть расширен, чтобы разрешить объявление следует ли объявлять закрывающие элементы изменчивыми или нет.

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

Я не знаю, является ли это единственной причиной, но похоже, что это было рассмотрено. Однако в предложении Herb Sutter он предлагает избавиться от mutable и не делать копии захвата неявно const, чтобы мы могли видеть изменения снова.

Ответ 2

Вероятно, надзор (так же, как rvalue refs не может быть использован) рода и артефакт того, как lambdas концептуально реализованы.

int   a;
int*  b;
float c;

auto lambda1 = [&a, b, c](int d) mutable -> void {};

class lambda1 {
public:
    void operator()(int d) {}
private:
    int&  a_;
    int*  b_;
    float c_;
};

auto lambda2 = [&a, b, c](int d) -> void {};

class lambda2 {
public:
    void operator()(int d) const {}
private:
    int&  a_;
    int*  b_;
    float c_;
};

Ответ 3

Ключевое слово mutable применяется к объекту, сгенерированному выражением лямбда, а не к индивидуально захваченным элементам, так что он может быть реализован компилятором с использованием модификатора const по методу operator(), как описано в разделе 5.1. 2, параграф 5 стандарта.

Этот оператор вызова функции объявляется const (9.3.1) тогда и только тогда, когда условие lambdaexpressions-declaration-statement не сопровождается изменяемые.

В вашем примере класс, сгенерированный выражением лямбда, может выглядеть так:

class lambda
{
  int a, b;

public:

  lambda( int a, int b ) : a( a ), b( b ) {}

  void operator()() // non-const due to mutable keyword
  {
    a = 7;
  }
};

Ответ 4

Ключевое слово mutable не используется, как правило, используется ключевое слово mutable: в данном случае оно означает противоположность const и применяется к константе оператора вызова функции, неявный функциональный объект, Однако было преднамеренно, что оператор вызова функции объекта неявной функции по умолчанию const, тогда как обычные функции-члены не являются const ( "mutable" ), но по умолчанию. Введение лямбда-функций предшествовало использованию контекстных ключевых слов (override и final), а ключевое слово mutable выглядело лучше, чем not const.