web-dev-qa-db-fra.com

Pourquoi l'opérateur d'appel d'un lambda est-il implicitement constant?

J'ai une petite "expression lambda" dans la fonction ci-dessous:

int main()
{
    int x = 10;
    auto lambda = [=] () { return x + 3; };
}

Ci-dessous, la "classe de fermeture anonyme" générée pour l'expression lambda ci-dessus.

int main()
{
    int x = 10;

    class __lambda_3_19
    {
        public: inline /*constexpr */ int operator()() const
        {
            return x + 3;
        }

        private:
            int x;

        public: __lambda_3_19(int _x) : x{_x}
          {}

    };

    __lambda_3_19 lambda = __lambda_3_19{x};
}

"Operator ()" de la fermeture généré par le compilateur est implicitement const. Pourquoi le comité standard l'a-t-il rendu const par défaut?

18
AImx1

De cppreference

Sauf si le mot clé mutable a été utilisé dans l'expression lambda, l'opérateur d'appel de fonction est qualifié de const et les objets capturés par copie ne sont pas modifiables à partir de cette operator().

Dans votre cas, il n’ya rien qui, capturé par copie, soit modifiable.

Je suppose que si vous écrivez quelque chose comme

int x = 10;

auto lambda = [=] () mutable { x += 3; return x; };

la const devrait disparaître

-- MODIFIER --

L'OP précis

Je savais déjà que l'ajout de mutable résoudrait le problème. La question est que je veux comprendre la raison pour rendre le lambda immuable par défaut.

Je ne suis pas juriste mais cela me semble évident: si vous faites operator() pas const, vous ne pouvez pas faire quelque chose comme

template <typename F>
void foo (F const & f)
 { f(); }

// ...

foo([]{ std::cout << "lambda!" << std::endl; });

Je veux dire ... si operator() n'est pas const, vous ne pouvez pas utiliser lambdas en les passant comme référence const.

Et quand ce n'est pas strictement nécessaire, cela devrait être une limitation inacceptable. 

9
max66

Trouvé ce papier par Herb Sutter à open-std.org qui discute de cette question.

Le couple impair: Capture par valeur injectée const et décalable mutable
Prenons l'exemple de cet exemple, où le programmeur capture une variable locale par valeur et tente de modifier la valeur capturée (qui est une variable membre de l'objet lambda):

int val = 0;
auto x = [=]( item e ) // look ma, [=] means explicit copy
 { use( e, ++val ); }; // error: count is const, need ‘mutable’
auto y = [val]( item e ) // darnit, I really can’t get more explicit
 { use( e, ++val ); }; // same error: count is const, need ‘mutable’

Cette fonctionnalité semble avoir été ajoutée pour éviter que l’utilisateur ne réalise pas qu’il en a reçu une copie, et en particulier parce que, puisque les lambdas sont copiables, il est peut-être en train de changer une copie différente.

La citation et l’exemple ci-dessus indiquent pourquoi le {pourrait} _ du Comité des normes l’a rendu const par défaut et a requis mutable pour le changer.

18
P.W

Je pense que c'est simplement pour éviter toute confusion lorsqu'une variable à l'intérieur d'un lambda ne fait pas référence à ce qui a été capturé à l'origine. Lexicalement, une telle variable est comme si elle était dans la portée de son "original". La copie est principalement destinée à permettre de prolonger la durée de vie d'un objet. Lorsqu'une capture n'est pas une copie, elle fait référence à l'original et les modifications sont appliquées à l'original. Il n'y a pas de confusion à cause de deux objets différents (dont l'un est implicitement introduit). Cette opération est autorisée par l'opérateur d'appel de fonction const de lambda.

0
guest