wake-up-neo.com

Warum ist der Aufrufoperator eines Lambdas implizit const?

Ich habe einen kleinen "Lambda-Ausdruck" in der folgenden Funktion:

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

Nachfolgend finden Sie die "anonyme Abschlussklasse", die für den obigen Lambda-Ausdruck generiert wurde.

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};
}

Der vom Compiler generierte "operator ()" des Abschlusses ist implizit const. Warum hat das Standardkomitee standardmäßig const festgelegt?

18
AImx1

Von cppreference

Wenn das Schlüsselwort mutable nicht im Lambda-Ausdruck verwendet wurde, ist der Funktionsaufruf-Operator const-qualifiziert, und die Objekte, die durch Kopieren erfasst wurden, können nicht innerhalb dieses operator()-Objekts geändert werden.

In Ihrem Fall gibt es nichts, was durch eine Kopie erfasst werden kann.

Ich vermute das, wenn du etwas schreibst

int x = 10;

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

das const sollte verschwinden

- BEARBEITEN -

Das OP genau

Ich wusste bereits, dass das Hinzufügen von veränderlichen das Problem lösen wird. Die Frage ist, dass ich den Grund dafür verstehen möchte, dass das Lambda standardmäßig unveränderlich ist.

Ich bin kein Sprachanwalt, aber das scheint mir offensichtlich: Wenn Sie operator() nicht const machen, können Sie nichts als machen

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

// ...

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

Ich meine ... wenn operator() nicht const ist, können Sie keine Lambdas als const-Referenz übergeben.

Und wenn dies nicht unbedingt erforderlich ist, sollte dies eine inakzeptable Einschränkung sein. 

9
max66

Fanden diese Papier von Herb Sutter bei open-std.org, die diese Angelegenheit diskutiert.

Das merkwürdige Paar: Erfassen Sie anhand der injizierten Konstante und der skurrilen veränderlichen Konstante des Werts.
Betrachten Sie dieses Strawman-Beispiel, in dem der Programmierer eine lokale Variable nach Wert erfasst und versucht, den erfassten Wert (der eine Mitgliedsvariable des Lambda-Objekts ist) zu ändern:

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’

Diese Funktion wurde anscheinend aus dem Grund hinzugefügt, dass der Benutzer möglicherweise nicht bemerkt, dass er eine Kopie erhalten hat, und dass er möglicherweise die Kopie eines anderen Lambdas ändert, da Lambdas kopierbar sind.

Das obige Zitat und Beispiel zeigen, warum das Normungskomitee könnte es standardmäßig zu const gemacht hat und mutable benötigt, um es zu ändern.

18
P.W

Ich denke, es ist einfach, Verwirrung zu vermeiden, wenn eine Variable in einem Lambda sich nicht auf das bezieht, was ursprünglich erfasst wurde. Lexikalisch ist eine solche Variable so, als ob sie in ihrem "Original" liegt. Das Kopieren dient hauptsächlich dazu, die Lebensdauer eines Objekts zu verlängern. Wenn ein Capture nicht kopiert wird, bezieht es sich auf das Original, und Änderungen werden auf das Original angewendet, und es gibt keine Verwirrung aufgrund zweier verschiedener Objekte (von denen eines implizit eingeführt wird). Dies wird vom Aufrufoperator const von Lambda erlaubt.

0
guest