Λάμδα εκφράσεις σε C ++

Lambda Expressions C



Γιατί Έκφραση Λάμδα;

Εξετάστε την ακόλουθη δήλωση:

intmyInt= 52?

Εδώ, το myInt είναι ένα αναγνωριστικό, μια τιμή. Το 52 είναι κυριολεκτικό, μια προτίμηση. Σήμερα, είναι δυνατή η κωδικοποίηση μιας συνάρτησης ειδικά και η τοποθέτησή της στη θέση 52. Μια τέτοια συνάρτηση ονομάζεται έκφραση λάμδα. Εξετάστε επίσης το ακόλουθο σύντομο πρόγραμμα:







#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intfn(intδιά μέσου)

{

intαπάντηση=διά μέσου+ 3?

ΕΠΙΣΤΡΟΦΗαπάντηση?

}


intκύριος()

{

fn(5)?



ΕΠΙΣΤΡΟΦΗ 0?

}

Σήμερα, είναι δυνατή η κωδικοποίηση μιας συνάρτησης ειδικά και η τοποθέτησή της στη θέση του ορίσματος 5, της κλήσης συνάρτησης, fn (5). Μια τέτοια συνάρτηση ονομάζεται έκφραση λάμδα. Η έκφραση λάμδα (συνάρτηση) σε αυτή τη θέση είναι μια τιμή.



Οποιαδήποτε κυριολεκτική εκτός από την κυριολεκτική συμβολοσειρά είναι prvalue. Η έκφραση λάμδα είναι ένας σχεδιασμός ειδικής λειτουργίας που θα ταιριάζει ως κυριολεκτικός στον κώδικα. Είναι μια ανώνυμη (ανώνυμη) συνάρτηση. Αυτό το άρθρο εξηγεί τη νέα κύρια έκφραση C ++, που ονομάζεται έκφραση λάμδα. Η βασική γνώση σε C ++ είναι απαραίτητη για την κατανόηση αυτού του άρθρου.



Περιεχόμενο άρθρου

Εικονογράφηση της έκφρασης Λάμδα

Στο ακόλουθο πρόγραμμα, μια συνάρτηση, η οποία είναι μια έκφραση λάμδα, εκχωρείται σε μια μεταβλητή:





#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

αυτοfn= [](intνα σταματήσει)

{

intαπάντηση=να σταματήσει+ 3?

ΕΠΙΣΤΡΟΦΗαπάντηση?

}?


intκύριος()

{

αυτοvariab=fn(2)?

κόστος <<variab<< ' n'?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

5

Εκτός της κύριας συνάρτησης (), υπάρχει η μεταβλητή, fn. Ο τύπος του είναι αυτόματος. Αυτόματα σε αυτήν την περίπτωση σημαίνει ότι ο πραγματικός τύπος, όπως int ή float, καθορίζεται από το δεξί τελεστή του τελεστή εκχώρησης (=). Στα δεξιά του τελεστή εκχώρησης υπάρχει μια έκφραση λάμδα. Μια έκφραση λάμδα είναι μια συνάρτηση χωρίς τον προηγούμενο τύπο επιστροφής. Σημειώστε τη χρήση και τη θέση των αγκύλων, []. Η συνάρτηση επιστρέφει 5, ένα int, το οποίο θα καθορίσει τον τύπο για το fn.



Στην κύρια συνάρτηση (), υπάρχει η δήλωση:

αυτοvariab=fn(2)?

Αυτό σημαίνει, fn εκτός main (), καταλήγει ως αναγνωριστικό μιας συνάρτησης. Οι έμμεσες παράμετροί του είναι αυτές της έκφρασης λάμδα. Ο τύπος για το variab είναι αυτόματος.

Σημειώστε ότι η έκφραση λάμδα τελειώνει με ερωτηματικό, όπως και ο ορισμός κλάσης ή δομής, τελειώνει με ερωτηματικό.

Στο ακόλουθο πρόγραμμα, μια συνάρτηση, η οποία είναι μια έκφραση λάμδα που επιστρέφει την τιμή 5, είναι ένα όρισμα σε μια άλλη συνάρτηση:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

κενόςαλλο(intΝο1,int (*ptr)(int))

{

intΝο2= (*ptr)(2)?

κόστος <<Νο1<< '' <<Νο2<< ' n'?

}


intκύριος()

{

αλλο(4,[](intνα σταματήσει)

{

intαπάντηση=να σταματήσει+ 3?

ΕΠΙΣΤΡΟΦΗαπάντηση?

})?


ΕΠΙΣΤΡΟΦΗ 0?
}

Η έξοδος είναι:

Τέσσερα πέντε

Υπάρχουν δύο συναρτήσεις εδώ, η έκφραση λάμδα και η συνάρτηση otherfn (). Η έκφραση λάμδα είναι το δεύτερο όρισμα του άλλουfn (), που καλείται στο κύριο (). Σημειώστε ότι η συνάρτηση λάμδα (έκφραση) δεν τελειώνει με ερωτηματικό σε αυτήν την κλήση επειδή, εδώ, είναι ένα όρισμα (όχι μια αυτόνομη συνάρτηση).

Η παράμετρος συνάρτησης λάμδα στον ορισμό της συνάρτησης otherfn () είναι δείκτης μιας συνάρτησης. Ο δείκτης έχει το όνομα, ptr. Το όνομα, ptr, χρησιμοποιείται στον ορισμό otherfn () για να καλέσετε τη συνάρτηση λάμδα.

Η ΔΗΛΩΣΗ,

intΝο2= (*ptr)(2)?

Στον ορισμό otherfn (), καλεί τη συνάρτηση λάμδα με ένα όρισμα 2. Η τιμή επιστροφής της κλήσης, '(*ptr) (2)' από τη συνάρτηση λάμδα, εκχωρείται στο νο2.

Το παραπάνω πρόγραμμα δείχνει επίσης πώς μπορεί να χρησιμοποιηθεί η λειτουργία λάμδα στο σχήμα συνάρτησης επανάκλησης C ++.

Μέρη της Έκφρασης Λάμδα

Τα μέρη μιας τυπικής συνάρτησης λάμδα είναι τα εξής:

[] () {}
  • [] είναι η ρήτρα σύλληψης. Μπορεί να έχει αντικείμενα.
  • () είναι για τη λίστα παραμέτρων.
  • {} είναι για το σώμα της λειτουργίας. Εάν η συνάρτηση στέκεται μόνη της, τότε θα πρέπει να τελειώσει με ερωτηματικό.

Συλλαμβάνει

Ο ορισμός της συνάρτησης λάμδα μπορεί να εκχωρηθεί σε μια μεταβλητή ή να χρησιμοποιηθεί ως όρισμα σε μια διαφορετική κλήση συνάρτησης. Ο ορισμός για μια τέτοια κλήση συνάρτησης πρέπει να έχει ως παράμετρο, έναν δείκτη μιας συνάρτησης, που αντιστοιχεί στον ορισμό της συνάρτησης λάμδα.

Ο ορισμός της συνάρτησης λάμδα διαφέρει από τον κανονικό ορισμό συνάρτησης. Μπορεί να αντιστοιχιστεί σε μια μεταβλητή στο παγκόσμιο πεδίο. αυτή η συνάρτηση που έχει εκχωρηθεί σε μεταβλητή μπορεί επίσης να κωδικοποιηθεί μέσα σε άλλη συνάρτηση. Όταν εκχωρείται σε μια μεταβλητή καθολικής εμβέλειας, το σώμα της μπορεί να δει άλλες μεταβλητές στην παγκόσμια εμβέλεια. Όταν εκχωρείται σε μια μεταβλητή μέσα σε έναν κανονικό ορισμό συνάρτησης, το σώμα της μπορεί να δει άλλες μεταβλητές στο εύρος συνάρτησης μόνο με τη βοήθεια της ρήτρας σύλληψης, [].

Η ρήτρα σύλληψης [], επίσης γνωστή ως λάμδα-εισαγωγέας, επιτρέπει την αποστολή μεταβλητών από το περιβάλλον λειτουργίας (λειτουργίας) στο σώμα λειτουργίας της έκφρασης λάμδα. Το σώμα λειτουργίας της έκφρασης λάμδα λέγεται ότι συλλαμβάνει τη μεταβλητή όταν λαμβάνει το αντικείμενο. Χωρίς τη ρήτρα σύλληψης [], μια μεταβλητή δεν μπορεί να σταλεί από το περιβάλλον πεδίο στο σώμα λειτουργίας της έκφρασης λάμδα. Το ακόλουθο πρόγραμμα απεικονίζει αυτό, με το κύριο πεδίο () συνάρτησης, ως το περιβάλλον πεδίο:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()

{

intταυτότητα= 5?


αυτοfn= [ταυτότητα]()

{

κόστος <<ταυτότητα<< ' n'?

}?

fn()?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι 5 Το Χωρίς το όνομα, id, εντός [], η έκφραση λάμδα δεν θα είχε δει τη μεταβλητή id του πεδίου κύριας () συνάρτησης.

Λήψη με αναφορά

Το παραπάνω παράδειγμα χρήσης της ρήτρας καταγραφής καταγράφει κατά τιμή (δείτε λεπτομέρειες παρακάτω). Κατά τη λήψη μέσω αναφοράς, η θέση (αποθήκευση) της μεταβλητής, π.χ., id παραπάνω, του περιβάλλοντος πεδίου, είναι διαθέσιμη μέσα στο σώμα της λειτουργίας λάμδα. Έτσι, η αλλαγή της τιμής της μεταβλητής στο σώμα της συνάρτησης λάμδα θα αλλάξει την τιμή της ίδιας μεταβλητής στο περιβάλλον πεδίο. Κάθε μεταβλητή που επαναλαμβάνεται στη ρήτρα σύλληψης προηγείται από το ampersand (&) για να επιτευχθεί αυτό. Το παρακάτω πρόγραμμα το δείχνει:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()

{

intταυτότητα= 5? φλοτέρft= 2.3? απανθρακώνωκεφ= 'ΠΡΟΣ ΤΟ'?

αυτοfn= [&ταυτότητα,&ft,&κεφ]()

{

ταυτότητα= 6?ft= 3.4?κεφ= 'ΣΙ'?

}?

fn()?

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ' n'?

ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

6, 3.4, Β

Επιβεβαιώνοντας ότι τα ονόματα μεταβλητών μέσα στο σώμα συνάρτησης της έκφρασης λάμδα είναι για τις ίδιες μεταβλητές εκτός της έκφρασης λάμδα.

Λήψη από την αξία

Κατά τη σύλληψη κατά τιμή, ένα αντίγραφο της θέσης της μεταβλητής, του περιβάλλοντος πεδίου, διατίθεται μέσα στο σώμα της συνάρτησης λάμδα. Αν και η μεταβλητή στο σώμα της λειτουργίας λάμδα είναι αντίγραφο, η τιμή της δεν μπορεί να αλλάξει στο εσωτερικό του σώματος από τώρα. Για να επιτευχθεί η καταγραφή κατά τιμή, κάθε μεταβλητή που επαναλαμβάνεται στη ρήτρα σύλληψης δεν προηγείται με τίποτα. Το παρακάτω πρόγραμμα το δείχνει:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()

{

intταυτότητα= 5? φλοτέρft= 2.3? απανθρακώνωκεφ= 'ΠΡΟΣ ΤΟ'?

αυτοfn= [id, ft, ch]()

{

// id = 6; ft = 3,4; ch = 'B';

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ' n'?

}?

fn()?

ταυτότητα= 6?ft= 3.4?κεφ= 'ΣΙ'?

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ' n'?

ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

5, 2.3, Α

6, 3.4, Β

Εάν αφαιρεθεί η ένδειξη σχολίου, το πρόγραμμα δεν θα μεταγλωττιστεί. Ο μεταγλωττιστής θα εκδώσει ένα μήνυμα σφάλματος ότι οι μεταβλητές μέσα στον ορισμό του σώματος συνάρτησης της έκφρασης λάμδα δεν μπορούν να αλλάξουν. Αν και οι μεταβλητές δεν μπορούν να αλλάξουν μέσα στη συνάρτηση λάμδα, μπορούν να αλλάξουν έξω από τη συνάρτηση λάμδα, όπως δείχνει η έξοδος του παραπάνω προγράμματος.

Mixing Captures

Η καταγραφή με αναφορά και η καταγραφή κατά τιμή μπορούν να συνδυαστούν, όπως δείχνει το ακόλουθο πρόγραμμα:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()

{

intταυτότητα= 5? φλοτέρft= 2.3? απανθρακώνωκεφ= 'ΠΡΟΣ ΤΟ'? μπουλbl= αληθής?


αυτοfn= [id, ft,&ch,&bl]()

{

κεφ= 'ΣΙ'?bl= ψευδής?

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ',' <<bl<< ' n'?

}?

fn()?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

5, 2.3, Β, 0

Όταν καταγραφούν όλα, γίνεται με αναφορά:

Εάν όλες οι μεταβλητές που πρόκειται να συλληφθούν καταγράφονται με αναφορά, τότε μόνο μία & θα αρκεί στη ρήτρα σύλληψης. Το παρακάτω πρόγραμμα το δείχνει:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()

{

intταυτότητα= 5? φλοτέρft= 2.3? απανθρακώνωκεφ= 'ΠΡΟΣ ΤΟ'? μπουλbl= αληθής?


αυτοfn= [&]()

{

ταυτότητα= 6?ft= 3.4?κεφ= 'ΣΙ'?bl= ψευδής?

}?

fn()?

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ',' <<bl<< ' n'?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

6, 3.4, Β, 0

Εάν ορισμένες μεταβλητές πρόκειται να συλληφθούν με αναφορά και άλλες με τιμή, τότε μία & θα αντιπροσωπεύει όλες τις αναφορές και στις υπόλοιπες δεν θα προηγείται τίποτα, όπως δείχνει το ακόλουθο πρόγραμμα:

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()

{

intταυτότητα= 5? φλοτέρft= 2.3? απανθρακώνωκεφ= 'ΠΡΟΣ ΤΟ'? μπουλbl= αληθής?


αυτοfn= [&, id, ft]()

{

κεφ= 'ΣΙ'?bl= ψευδής?

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ',' <<bl<< ' n'?

}?

fn()?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

5, 2.3, Β, 0

Σημειώστε ότι & μόνο (δηλαδή, & δεν ακολουθείται από αναγνωριστικό) πρέπει να είναι ο πρώτος χαρακτήρας στη ρήτρα καταγραφής.

Όταν όλα καταγράφονται, είναι κατά αξία:

Εάν όλες οι μεταβλητές που πρόκειται να συλληφθούν πρόκειται να συλληφθούν με τιμή, τότε μόνο μία = θα αρκεί στη ρήτρα σύλληψης. Το παρακάτω πρόγραμμα το δείχνει:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()
{

intταυτότητα= 5? φλοτέρft= 2.3? απανθρακώνωκεφ= 'ΠΡΟΣ ΤΟ'? μπουλbl= αληθής?


αυτοfn= [=]()

{

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ',' <<bl<< ' n'?

}?

fn()?


ΕΠΙΣΤΡΟΦΗ 0?


}

Η έξοδος είναι:

5, 2.3, Α, 1

Σημείωση : = είναι μόνο για ανάγνωση, από τώρα.

Εάν ορισμένες μεταβλητές πρόκειται να καταγραφούν με τιμή και άλλες με αναφορά, τότε μία = θα αντιπροσωπεύει όλες τις μεταβλητές που έχουν αντιγραφεί μόνο για ανάγνωση και οι υπόλοιπες θα έχουν &, όπως δείχνει το ακόλουθο πρόγραμμα:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

intκύριος()

{

intταυτότητα= 5? φλοτέρft= 2.3? απανθρακώνωκεφ= 'ΠΡΟΣ ΤΟ'? μπουλbl= αληθής?


αυτοfn= [=,&ch,&bl]()

{

κεφ= 'ΣΙ'?bl= ψευδής?

κόστος <<ταυτότητα<< ',' <<ft<< ',' <<κεφ<< ',' <<bl<< ' n'?

}?

fn()?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

5, 2.3, Β, 0

Σημειώστε ότι = μόνο πρέπει να είναι ο πρώτος χαρακτήρας στη ρήτρα σύλληψης.

Κλασικό σχήμα λειτουργίας επαναφοράς με έκφραση Λάμδα

Το παρακάτω πρόγραμμα δείχνει πώς μπορεί να γίνει ένα κλασικό σχήμα συνάρτησης κλήσης με την έκφραση λάμδα:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

απανθρακώνω *παραγωγή?


αυτοcba= [](απανθρακώνωέξω[])

{

παραγωγή=έξω?

}?



κενόςmainFunc(απανθρακώνωεισαγωγή[],κενός (*Για)(απανθρακώνω[]))

{

(*Για)(εισαγωγή)?

κόστος<<«για κύρια λειτουργία»<<' n'?

}


κενόςfn()

{

κόστος<<'Τώρα'<<' n'?

}


intκύριος()

{

απανθρακώνωεισαγωγή[] = 'για λειτουργία επανάκλησης'?

mainFunc(εισαγωγή, cba)?

fn()?

κόστος<<παραγωγή<<' n'?



ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι:

για κύρια λειτουργία

Τώρα

για τη λειτουργία επανάκλησης

Θυμηθείτε ότι όταν ένας ορισμός έκφρασης λάμδα εκχωρείται σε μια μεταβλητή στο παγκόσμιο πεδίο, το σώμα της λειτουργίας του μπορεί να δει καθολικές μεταβλητές χωρίς να χρησιμοποιήσει τη ρήτρα καταγραφής.

Ο τύπος πίσω-επιστροφής

Ο τύπος επιστροφής μιας έκφρασης λάμδα είναι αυτόματος, που σημαίνει ότι ο μεταγλωττιστής καθορίζει τον τύπο επιστροφής από την έκφραση επιστροφής (εάν υπάρχει). Εάν ο προγραμματιστής θέλει πραγματικά να υποδείξει τον τύπο επιστροφής, τότε θα το κάνει όπως στο ακόλουθο πρόγραμμα:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

αυτοfn= [](intνα σταματήσει) ->> int

{

intαπάντηση=να σταματήσει+ 3?

ΕΠΙΣΤΡΟΦΗαπάντηση?

}?


intκύριος()

{

αυτοvariab=fn(2)?

κόστος <<variab<< ' n'?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι 5. Μετά τη λίστα παραμέτρων, πληκτρολογείται ο τελεστής βέλους. Ακολουθεί ο τύπος επιστροφής (int σε αυτήν την περίπτωση).

Κλείσιμο

Εξετάστε το ακόλουθο τμήμα κώδικα:

δομήΚλα

{

intταυτότητα= 5?

απανθρακώνωκεφ= 'προς το'?

}obj1, obj2?

Εδώ, Cla είναι το όνομα της κλάσης struct. Το Obj1 και το obj2 είναι δύο αντικείμενα που θα προταθούν από την κλάση struct. Η έκφραση Λάμδα είναι παρόμοια στην εφαρμογή. Ο ορισμός της συνάρτησης λάμδα είναι ένα είδος κλάσης. Όταν η συνάρτηση λάμδα καλείται (επικαλείται), ένα αντικείμενο υποδεικνύεται από τον ορισμό του. Αυτό το αντικείμενο ονομάζεται κλείσιμο. Είναι το κλείσιμο που κάνει τη δουλειά που αναμένεται να κάνει η λάμδα.

Ωστόσο, η κωδικοποίηση της έκφρασης λάμδα όπως το παραπάνω struct θα έχει obj1 και obj2 που θα αντικατασταθούν από τα επιχειρήματα των αντίστοιχων παραμέτρων. Το παρακάτω πρόγραμμα το δείχνει:

#περιλαμβάνω

χρησιμοποιώντας ονομαστικου χωρουώρες?

αυτοfn= [](intparam1,intparam2)

{

intαπάντηση=param1+param2?

ΕΠΙΣΤΡΟΦΗαπάντηση?

} (2,3)?


intκύριος()

{

αυτοόπου=fn?

κόστος <<όπου<< ' n'?


ΕΠΙΣΤΡΟΦΗ 0?

}

Η έξοδος είναι 5. Τα ορίσματα είναι 2 και 3 σε παρένθεση. Σημειώστε ότι η κλήση συνάρτησης έκφρασης λάμδα, fn, δεν λαμβάνει κανένα όρισμα, αφού τα ορίσματα έχουν ήδη κωδικοποιηθεί στο τέλος του ορισμού της συνάρτησης λάμδα.

συμπέρασμα

Η έκφραση λάμδα είναι μια ανώνυμη συνάρτηση. Αποτελείται από δύο μέρη: κλάση και αντικείμενο. Ο ορισμός του είναι ένα είδος τάξης. Όταν καλείται η έκφραση, ένα αντικείμενο σχηματίζεται από τον ορισμό. Αυτό το αντικείμενο ονομάζεται κλείσιμο. Είναι το κλείσιμο που κάνει τη δουλειά που αναμένεται να κάνει η λάμδα.

Για να λάβει η έκφραση λάμδα μια μεταβλητή από ένα εξωτερικό πεδίο συνάρτησης, χρειάζεται μια κενή ρήτρα σύλληψης στο σώμα της συνάρτησης.