GOOGLE ADS

Samstag, 23. April 2022

Wenn aus Lambda-Ausdrücken generierte Klassen keinen Standardctor haben, wie kann dann ein Objekt dieses generierten Klassentyps erstellt werden?

Ich lerne C++ mit der hier aufgeführten Ressource. Insbesondere habe ich in C++ Primer von Lippman über Lambda-Ausdrücke gelesen. Dort erfuhr ich, dass Lambdas Funktionsobjekte sind. Darüber hinaus haben aus Lambda-Ausdrücken generierte Klassen keinen Standardkonstruktor. Also nimm zum Beispiel:

auto wc = find_if(words.begin(), words.end(),
[sz](const string &a){
return s.size() >= sz;
};

Es steht geschrieben, dass der obige Lambda-Ausdruck eine Klasse generiert, die in etwa so aussieht:

class SizeComp {
SizeComp(size_t n): sz(n) { } // parameter for each captured
variable
// call operator with the same return type, parameters, and body as the lambda
bool operator()(const string &s) const
{ return s.size() >= sz; }
private:
size_t sz; // a data member for each variable captured by value
};

Was also passiert, ist, dass ein unbenanntes Objekt dieser vom Compiler generierten Klasse erstellt und als drittes Argument an die std::find_ifoben gezeigte übergeben wird. Ich kann das verstehen.

Nun ist es mein Denken/Verstehen, dass, da diese vom Compiler generierte Klasse keinen Standard-Ctor hat, das dritte Argument, das an übergeben wird, std::find_ifnicht mit einem Standard-Ctor erstellt werden darf, da dies fehlschlagen würde. Intern sollte das übergebene Objekt also mit dem parametrisierten ctor wie folgt erstellt werden:

auto wc = find_if(words.begin(), words.end(), SizeComp(sz)); //note the third argument uses the parameterized ctor

Meine erste Frage ist, dass, da es im Falle einer leeren Erfassungsliste in C++11 keinen Standardctor gibt, wie also ein Objekt dieser vom Compiler generierten Klasse erstellt wird. Ich meine, im Falle einer leeren Erfassungsliste gibt es keine Datenmitglieder in der vom Compiler generierten Klasse, sodass es keinen parametrisierten ctor gibt. Das bedeutet, dass diese vom Compiler generierte Klasse weder einen Standard- noch einen parametrisierten ctor hat. Wie kann dann ein Objekt dieser Klasse generiert werden? Die unten gezeigte Situation funktioniert beispielsweise nicht, wenn die Erfassungsliste leer ist:

auto wc = find_if(words.begin(), words.end(),
[](const string &a){ //NOTE THE CAPTURE LIST IS EMPTY
return s.size() >= 5;
};

Wie wird nun das dritte Argument std::find_iferstellt:

auto wc = find_if(words.begin(), words.end(), CompGeneratedClass()); //this can't work because there is no default ctor

Ich weiß auch, dass der Compiler für eine normale/gewöhnliche benutzerdefinierte Klasse, wenn wir einen benutzerdefinierten Ctor bereitstellen, keinen Standard-Ctor für diese Klasse generiert. Es scheint mir also, dass der Compiler einen Standard-Ctor für diese vom Compiler generierte Klasse generieren sollte, da es im Falle eines leeren Capture-List-Lambda-Ausdrucks keinen benutzerdefinierten Ctor gibt. Aber der C++-Standard besagt, dass es keinen Standardctor geben wird. Meine zweite Frage ist also, warum sich diese vom Compiler generierte Klasse anders verhält als eine benutzerdefinierte Klasse.


Lösung des Problems

Das Problem hier ist das der Gemütsverfassung. Während die Einführung das Verhalten auf eine Weise erklärt, die man leicht verstehen kann, ist es nicht wörtlich zu nehmen. Der normative Text beschreibt Verhalten, nicht Wege, es zu erreichen. Ein Compiler muss eine Klasse nicht so erstellen, wie wir es tun.

Beispielsweise kann ein Anbieter immer ein geheimes Tag in die Parameterliste des Konstruktors einschleusen. Stellen Sie sich vor, dies wird generiert:

struct __secret_tag_at_src_line{};
struct __lambda_at_src_line{
__lambda_at_src_line(__secret_tag_at_src_line, /*Other arguments*/)
//...
};
//...
auto wc = find_if(words.begin(), words.end(), __lambda_at_src_line(__secret_tag_at_src_line{},...)};

Wir können dieses Tag nicht benennen oder auch nur von seiner Existenz wissen, also können wir das Lambda nicht in einer anderen Zeile erstellen. Und die Klasse wird niemals einen Standardkonstruktor haben. Das ist ein Weg, es zu tun. Aber selbst dann muss ein Compiler das nicht tun.

Die Durchführung unterliegt nicht denselben Regeln wie wir; Der Standard lässt großen Spielraum für Implementierungen, solange das Programm korrekt übersetzt wird. Ein Compiler könnte einfach ein Byte segnen und sagen: "Dies ist ein Lambda", ohne dass ein Konstruktor aufgerufen werden muss. Wieso den?! Weil es erfüllt, was der Standard sagt; das beobachtbare Verhalten ist intakt (denken Sie darüber nach, kann die Initialisierung eines Capture-less-Lambda von einem C++-Programm beobachtet werden?)

Manchmal müssen Implementierungen "schummeln"; Verdammt, es ist bekannt, dass Implementierungen private Konstruktoren aufrufen, um die Arbeit zu erledigen. Aber es ist nicht wirklich Betrug, weil die gleichen Regeln nicht gelten.

Keine Kommentare:

Kommentar veröffentlichen

Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...