Ich verstehe die richtige Art zu erfassen this
(Ändern von Objekteigenschaften) in einem Lambda wie folgt:
auto f = [this] () { /* ... */ };
Aber ich bin neugierig auf die folgende Besonderheit, die ich gesehen habe:
class C {
public:
void foo() {
// auto f = [] () { // this not captured
auto f = [&] () { // why does this work?
// auto f = [&this] () { // Expected ',' before 'this'
// auto f = [this] () { // works as expected
x = 5;
};
f();
}
private:
int x;
};
Die Kuriosität, die mich verwirrt (und die ich gerne beantwortet hätte), ist, warum Folgendes funktioniert:
auto f = [&] () { /* ... */ }; // capture everything by reference
Und warum ich nicht explizit this
durch Bezugnahme erfassen kann :
auto f = [&this] () { /* ... */ }; // a compiler error as seen above.
this
Kann nicht geändert werden, ist nicht groß genug, um einen Verweis schneller zu machen ... und trotzdem existiert er nicht wirklich , also hat er Keine wirkliche Lebensdauer, was bedeutet, dass ein Hinweis darauf per Definition baumeln würde.this
ist ein Wert, kein Wert.Antworten:
Der Grund
[&this]
dafür ist, dass es sich um einen Syntaxfehler handelt. Jeder durch Kommas getrennte Parameter inlambda-introducer
ist eincapture
:Sie können sehen, dass
&this
dies syntaktisch nicht zulässig ist. Der Grund, warum dies nicht zulässig ist, liegt darin, dass Sie niemalsthis
als Referenz erfassen möchten , da es sich um einen kleinen const-Zeiger handelt. Sie möchten es immer nur als Wert übergeben - daher unterstützt die Sprache die Erfassung einfach nichtthis
Referenz .Um
this
explizit zu erfassen , können Sie[this]
als verwendenlambda-introducer
.Das erste
capture
kann ein sein,capture-default
das ist:Dies bedeutet, dass automatisch erfasst wird, was auch immer ich verwende, nach Referenz (
&
) bzw. nach Wert (=
) - die Behandlung vonthis
ist jedoch etwas Besonderes - in beiden Fällen wird es aus den zuvor angegebenen Gründen nach Wert erfasst (auch bei einer Standarderfassung von)&
, was normalerweise bedeutet Erfassung durch Referenz).5.1.2.7/8:
Das Lambda verhält sich also so, als ob es Teil der einschließenden Elementfunktion ist, wenn Elementnamen verwendet werden (wie in Ihrem Beispiel die Verwendung des Namens
x
), und generiert daher "implizite Verwendungen"this
wie bei einer Elementfunktion.So Sie verwenden können
[this]
,[&]
,[=]
oder[&,this]
alslambda-introducer
das erfassenthis
Zeiger nach Wert.Jedoch
[&this]
und[=, this]
sind schlecht geformt. Im letzten Fall gcc warnt forgivingly für[=,this]
dieexplicit by-copy capture of ‘this’ redundant with by-copy capture default
eher als Fehler.quelle
[&]
wenn Sie so etwas wie einen Block erstellen, der an eine Kontrollstruktur übergeben werden soll", aber explizit erfassen, wenn Sie ein Lambda produzieren, das für weniger einfache Zwecke verwendet werden soll.[&]
ist eine schreckliche Idee, wenn das Lambda den gegenwärtigen Umfang überleben wird. Viele Verwendungen von Lambdas sind jedoch nur Möglichkeiten, Blöcke an Kontrollstrukturen zu übergeben, und der Block überlebt den Block, den er im Gültigkeitsbereich erstellt hat, nicht.this
ist ein Schlüsselwort,this
kein Bezeichner.Weil Standard nicht
&this
in Captures-Listen hat:N4713 8.4.5.2 Erfassungen:
Standard garantiert
this
und*this
ist gültig und&this
ungültig. Erfassenthis
bedeutet auch*this
, dass das Objekt selbst als Referenz erfasst wird (was ein Wert ist, das Objekt selbst) , anstatt denthis
Zeiger nach Wert zu erfassen !quelle
*this
erfasst das Objekt nach Wert