Περισσότερα
Τι είναι η έκφραση λάμδα στη C++11;
Τι είναι η έκφραση λάμδα στη C++11; Πότε μπορώ να τη χρησιμοποιήσω; Ποια κατηγορία προβλημάτων επιλύουν που δεν ήταν δυνατή πριν από την εισαγωγή τους;
Μερικά παραδείγματα και περιπτώσεις χρήσης θα ήταν χρήσιμα.
1398
3
Το πρόβλημα
Η C++ περιλαμβάνει χρήσιμες γενικές συναρτήσεις όπως οι
std::for_each
καιstd::transform
, οι οποίες μπορεί να είναι πολύ χρήσιμες. Δυστυχώς, μπορεί επίσης να είναι αρκετά δυσκίνητες στη χρήση τους, ιδιαίτερα αν ο functor που θέλετε να εφαρμόσετε είναι μοναδικός για τη συγκεκριμένη συνάρτηση.Αν χρησιμοποιείτε την
f
μόνο μία φορά και σε αυτό το συγκεκριμένο σημείο, φαίνεται υπερβολικό να γράφετε μια ολόκληρη κλάση μόνο και μόνο για να κάνετε κάτι ασήμαντο και μοναδικό.Στη C++03 θα μπορούσατε να μπείτε στον πειρασμό να γράψετε κάτι σαν το παρακάτω, για να διατηρήσετε τον τελεστή τοπικά:
ωστόσο αυτό δεν επιτρέπεται, το
f
δεν μπορεί να περάσει σε μια συνάρτηση [template][1] στη C++03.Η νέα λύση
Η C++11 εισάγει τα lambdas που σας επιτρέπουν να γράψετε έναν inline, ανώνυμο συναρτησιακό για να αντικαταστήσετε το
struct f
. Για μικρά απλά παραδείγματα αυτό μπορεί να είναι πιο καθαρό στην ανάγνωση (κρατάει τα πάντα σε ένα μέρος) και ενδεχομένως πιο απλό στη συντήρηση, για παράδειγμα στην απλούστερη μορφή:Οι συναρτήσεις λάμδα είναι απλά συντακτική ζάχαρη για ανώνυμους συναρτησιακούς παράγοντες.
Τύποι επιστροφής
Σε απλές περιπτώσεις ο τύπος επιστροφής της λάμδα προκύπτει για εσάς, π.χ:
ωστόσο όταν αρχίζετε να γράφετε πιο σύνθετες λάμδα θα συναντήσετε γρήγορα περιπτώσεις όπου ο τύπος επιστροφής δεν μπορεί να εξαχθεί από τον μεταγλωττιστή, π.χ.:
Για να το επιλύσετε αυτό, σας επιτρέπεται να καθορίσετε ρητά έναν τύπο επιστροφής για μια συνάρτηση λάμδα, χρησιμοποιώντας
-> T
:"Σύλληψη" μεταβλητών
Μέχρι στιγμής δεν'έχουμε χρησιμοποιήσει τίποτα άλλο εκτός από αυτό που έχει περάσει στη λάμδα μέσα σε αυτήν, αλλά μπορούμε να χρησιμοποιήσουμε και άλλες μεταβλητές, μέσα στη λάμδα. Αν θέλετε να αποκτήσετε πρόσβαση σε άλλες μεταβλητές, μπορείτε να χρησιμοποιήσετε τη ρήτρα σύλληψης (το
[]
της έκφρασης), η οποία μέχρι στιγμής δεν έχει χρησιμοποιηθεί σε αυτά τα παραδείγματα, π.χ.:Μπορείτε να συλλάβετε τόσο με αναφορά όσο και με τιμή, τις οποίες μπορείτε να καθορίσετε χρησιμοποιώντας
&
και=
αντίστοιχα:[&epsilon]
σύλληψη με αναφορά[&]
συλλαμβάνει όλες τις μεταβλητές που χρησιμοποιούνται στη λάμδα με αναφορά[=]
συλλαμβάνει όλες τις μεταβλητές που χρησιμοποιούνται στη λάμδα με τιμή[&, epsilon]
συλλαμβάνει μεταβλητές όπως με [&], αλλά το epsilon με τιμή[=, &epsilon]
συλλαμβάνει μεταβλητές όπως με [=], αλλά το epsilon με αναφοράΟ παραγόμενος
operator()
είναιconst
από προεπιλογή, με το συμπέρασμα ότι οι συλλήψεις θα είναιconst
όταν έχετε πρόσβαση σε αυτές από προεπιλογή. Αυτό έχει ως αποτέλεσμα κάθε κλήση με την ίδια είσοδο να παράγει το ίδιο αποτέλεσμα, ωστόσο μπορείτε να [επισημάνετε τη λάμδα ωςmutable
][2] για να ζητήσετε οoperator()
που παράγεται να μην είναιconst
.Τι είναι η συνάρτηση lambda;
Η έννοια της συνάρτησης λάμδα της C++ προέρχεται από τον λογισμό λάμδα και τον συναρτησιακό προγραμματισμό. Μια λάμδα είναι μια ανώνυμη συνάρτηση που είναι χρήσιμη (στον πραγματικό προγραμματισμό, όχι στη θεωρία) για σύντομα κομμάτια κώδικα που είναι αδύνατο να επαναχρησιμοποιηθούν και δεν αξίζει να ονομαστούν.
Στη C++ μια συνάρτηση λάμδα ορίζεται ως εξής
ή σε όλο της το μεγαλείο
[]
είναι ο κατάλογος σύλληψης,()
ο κατάλογος επιχειρημάτων και{}
το σώμα της συνάρτησης.Η λίστα σύλληψης
Η λίστα σύλληψης ορίζει τι από το εξωτερικό της λάμδα θα πρέπει να είναι διαθέσιμο μέσα στο σώμα της συνάρτησης και πώς. Μπορεί να είναι είτε:
Μπορείτε να συνδυάσετε οποιαδήποτε από τα παραπάνω σε μια λίστα διαχωρισμένη με κόμμα
[x, &y]
.Ο κατάλογος επιχειρημάτων
Ο κατάλογος των επιχειρημάτων είναι ο ίδιος όπως σε οποιαδήποτε άλλη συνάρτηση της C++.
Το σώμα της συνάρτησης
Ο κώδικας που θα εκτελεστεί όταν κληθεί πραγματικά η lambda.
Αφαίρεση τύπου επιστροφής
Εάν μια λάμδα έχει μόνο μια δήλωση επιστροφής, ο τύπος επιστροφής μπορεί να παραλειφθεί και έχει τον έμμεσο τύπο
decltype(return_statement)
.Μεταβλητή
Εάν μια λάμδα χαρακτηρίζεται ως μεταλλάξιμη (π.χ.
[]() mutable { }
) επιτρέπεται να μεταλλάσσει τις τιμές που έχουν συλληφθεί από την value.Περιπτώσεις χρήσης
Η βιβλιοθήκη που ορίζεται από το πρότυπο ISO επωφελείται σε μεγάλο βαθμό από τις λάμδα και ανεβάζει την ευχρηστία αρκετά ψηλά καθώς πλέον οι χρήστες δεν χρειάζεται να γεμίζουν τον κώδικά τους με μικρούς functors σε κάποια προσβάσιμη εμβέλεια.
C++14
Στη C++14 οι lambdas έχουν επεκταθεί με διάφορες προτάσεις.
Αρχικοποιημένες συλλήψεις λάμδα
Ένα στοιχείο της λίστας σύλληψης μπορεί τώρα να αρχικοποιηθεί με
=
. Αυτό επιτρέπει τη μετονομασία των μεταβλητών και τη σύλληψη με μετακίνηση. Ένα παράδειγμα που λαμβάνεται από το πρότυπο:και ένα παρμένο από τη Wikipedia που δείχνει πώς να συλλάβετε με το
std::move
:Γενικές Lambdas
Οι Lambdas μπορούν τώρα να είναι γενικές (το
auto
θα ήταν ισοδύναμο με τοT
εδώ ανT
ήταν ένα όρισμα προτύπου τύπου κάπου στην περιβάλλουσα εμβέλεια):Βελτιωμένη αφαίρεση τύπου επιστροφής
Η C++14 επιτρέπει την εξαγωγή τύπων επιστροφής για κάθε συνάρτηση και δεν την περιορίζει σε συναρτήσεις της μορφής
return expression;
. Αυτό επεκτείνεται και στις lambdas.Οι εκφράσεις Lambda χρησιμοποιούνται συνήθως για την ενθυλάκωση αλγορίθμων, ώστε να μπορούν να μεταβιβαστούν σε μια άλλη συνάρτηση. Ωστόσο, είναι δυνατή η εκτέλεση μιας lambda αμέσως μετά τον ορισμό της:
είναι λειτουργικά ισοδύναμη με
Αυτό καθιστά τις εκφράσεις λάμδα ένα ισχυρό εργαλείο για την αναδόμηση πολύπλοκων συναρτήσεων. Ξεκινάτε τυλίγοντας ένα τμήμα κώδικα σε μια συνάρτηση λάμδα, όπως φαίνεται παραπάνω. Η διαδικασία της ρητής παραμετροποίησης μπορεί στη συνέχεια να εκτελεστεί σταδιακά με ενδιάμεσες δοκιμές μετά από κάθε βήμα. Μόλις έχετε παραμετροποιήσει πλήρως το τμήμα κώδικα (όπως φαίνεται από την αφαίρεση του
&
), μπορείτε να μεταφέρετε τον κώδικα σε μια εξωτερική θέση και να τον κάνετε μια κανονική συνάρτηση.Ομοίως, μπορείτε να χρησιμοποιήσετε εκφράσεις λάμδα για να αρχικοποιήσετε μεταβλητές με βάση το αποτέλεσμα ενός αλγορίθμου...
Ως ένας τρόπος διαμερισμού της λογικής του προγράμματός σας, μπορεί ακόμη και να σας φανεί χρήσιμο να περάσετε μια έκφραση λάμδα ως όρισμα σε μια άλλη έκφραση λάμδα...
Οι εκφράσεις λάμδα σας επιτρέπουν επίσης να δημιουργήσετε ονομαστικές ενεστωμένες συναρτήσεις, οι οποίες μπορεί να είναι ένας βολικός τρόπος αποφυγής διπλής λογικής. Η χρήση επώνυμων λάμδα τείνει επίσης να είναι λίγο πιο εύκολη στα μάτια (σε σύγκριση με τις ανώνυμες inline λάμδα) όταν περνάτε μια μη τετριμμένη συνάρτηση ως παράμετρο σε μια άλλη συνάρτηση. Σημείωση: μην ξεχνάτε την άνω τελεία μετά την κλειστή τεθλασμένη αγκύλη.
Αν η μετέπειτα σκιαγράφηση προφίλ αποκαλύψει σημαντική επιβάρυνση αρχικοποίησης για το αντικείμενο της συνάρτησης, μπορεί να επιλέξετε να το ξαναγράψετε ως κανονική συνάρτηση.