Lambda Expression and auto
-
Hi,
ich habe zwar keine Frage, aber muss das trotzdem mit euch teilen. Vielleicht inspiriert das den ein oder anderen ja. Wenn wir öfters so kleine C++11 Codestücken untereinander teilen, kommen wir alle schneller vorwärts

#include <iostream> #include <functional> #include <string> using namespace std; function<string (const string& str)> makeStringAppender(const string& appy) { return [=](const string& str) { return str+appy; }; } int main() { auto textAppender = makeStringAppender(".txt"); auto jpegAppender = makeStringAppender(".jpg"); auto s1 = jpegAppender("Urlaub"), s3 = jpegAppender("Bild1"); auto s2 = textAppender("Doku"); cout << s1 << " " << s2 << " " << s3 << endl; }Einfach toll und sieht auch noch gut aus!!!
-
Das funktioniert wahrscheinlich nur, weil beispielsweise ".txt" im Datensegment liegt und ein konstanter Zeiger ist.
-
knivil schrieb:
Das funktioniert wahrscheinlich nur, weil beispielsweise ".txt" im Datensegment liegt und ein konstanter Zeiger ist.
Wenn ich raten müsste, würde ich sagen, du glaubst, dass [=] "nur die Referenz appy kopiert". Tatsächlich speichert die Lambdafunktion einen std::string (und keine Referenz auf einen String). Deswegen sehe ich hier auch keinerlei Probleme.
-
Ich habe heute dafür einen tollen Anwendungszweck endeckt.
#include <iostream> #include <functional> #include <string> using namespace std; struct Node { int data; Node(int d) : data(d), leftChild(nullptr), rightChild(nullptr) { } Node *leftChild; Node *rightChild; }; function<void (Node* node)> makePostOrderFunction(function<void (Node *node)> nodeFunction) { function<void (Node* node)> postOrder; postOrder = [&](Node* node) { if(node == nullptr) return; postOrder(node->leftChild); postOrder(node->rightChild); nodeFunction(node); }; return postOrder; } void printNode(Node *node) { cout << node->data << endl; } void getCoolNode(Node *node) { if(node->data % 2) /*insert into my cool vector*/; } int main() { Node *root = new Node(1); root->leftChild = new Node(2); root->rightChild = new Node(3); auto printTree = makePostOrderFunction(printNode); auto findCoolNodes = makePostOrderFunction(getCoolNode); printTree(root); findCoolNodes(root); }So kann ich mir nach belieben postOrder-Funktionen generieren, die auch noch named sind. Wobei man auch einfach so hätte machen können:
void postOrderOperation(Node *node, function<void (Node *node)> operation) { if(node == nullptr) return; postOrderOperation(node->leftChild, operation); postOrderOperation(node->rightChild, operation); operation(node); } auto printTree = [&](Node *node) { postOrderOperation(node, printNode); }; printTree(root);Oder doch direkt so:
function<void (Node* node)> makePostOrderOperation(function<void (Node *node)> nodeFunction) { return [&](Node *node) { postOrderOperation(node, nodeFunction); }; } auto printTree = makePostOrderOperation(printNode); printTree(root);Achja, hat doch nicht so viel gebracht

-
[&](Node *node) { postOrderOperation(node, nodeFunction); }So gibst du doch indirekt eine Referenz auf ein lokales Objekt zurück (
postOrderOperation)! Ändere den lambda-introducer zu[=], dann klappt das.
-
Klappt doch so. Das lokale Objekte ist hier zwar nodeFunction, aber das closure object wird doch bei der Rückgabe kopiert und dadurch sollte hier imho keine dangling reference entstehen.
Aber prinzipiell sollte da doch lieber ein [=] hin.
-
aber das closure object wird doch bei der Rückgabe kopiert
Was dann?
§5.1.2 / 15 schrieb:
It is unspecified whether additional unnamed non-static data members are declared in the closure type for entities captured by reference
Wodurch beim implizit definierten Kopierkonstruktor natürlich kein solches von dir beschriebenes Verhalten entstehen muss;

§5.1.2 / 22 schrieb:
If an entity is implicitly or explicitly captured by reference, invoking the function call operator of the corresponding lambda-expression after the lifetime of the entity has ended is likely to result in undefined behavior
Wobei ich hier etwas unsicher bin, ob "corresponding lambda expression" auch alle Kopien davon mit einschließt.
-
Sone schrieb:
§5.1.2 / 22:
If an entity is implicitly or explicitly captured by reference, invoking the function call operator of the corresponding lambda-expression after the lifetime of the entity has ended is likely to result in undefined behavior
Tue ich doch nicht. Durch die Rückgabe wird die Referenz, also der Wert dahinter, kopiert und der Lambda-Aufruf geschieht erst nach dieser Kopie.
-
Gabs da mal nicht einen hübschen Artikel zur Lebensdauer von Lambdas? Herb, Meyers, ... hmmm