User Tools

Site Tools


cpp:lamdas

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
cpp:lamdas [2026/05/21 21:33] – [Παραδείγματα Lamda] gthanoscpp:lamdas [2026/05/22 08:13] (current) – [Παράδειγμα 1ο - Φιλτράρισμα και εξαγωγή μέσου όρου] gthanos
Line 26: Line 26:
  
 ===== Παραδείγματα Lamda Expressions ===== ===== Παραδείγματα Lamda Expressions =====
 +
 +==== Παράδειγμα 1ο - Φιλτράρισμα και εξαγωγή μέσου όρου ====
  
 Στο παρακάτω παράδειγμα οι βαθμοί ενός φοιτητής, φιλτράρονται ως προς την προσβασιμοτητας τους και από αυτούς υπολογίζεται άθροισμα και πλήθος, ώστε να εξαχθεί ο μέσος όρος. Στο παρακάτω παράδειγμα οι βαθμοί ενός φοιτητής, φιλτράρονται ως προς την προσβασιμοτητας τους και από αυτούς υπολογίζεται άθροισμα και πλήθος, ώστε να εξαχθεί ο μέσος όρος.
Line 59: Line 61:
 Παρατηρούμε ότι το //Capture Clause// λαμβάνει τις μεταβλητές sum, count, threshold. Οι δύο πρώτες καλούνται με αναφορά και την ενημερώνουην μετά την έξοδο από τη lamda, ενώ η threshold καλείται με τιμή. Παρατηρούμε ότι το //Capture Clause// λαμβάνει τις μεταβλητές sum, count, threshold. Οι δύο πρώτες καλούνται με αναφορά και την ενημερώνουην μετά την έξοδο από τη lamda, ενώ η threshold καλείται με τιμή.
 </WRAP> </WRAP>
 +
 +=== Πως διαχειρίζεται ο compiler το lambda expression; ===
 +
 +Ο compiler μετατρέπει τη λάμδα σε μια ανώνυμη κλάση (anonymous functor). Για την παραπάνω έκφραση //lamda// ο compiler δημιουργεί την παρακάτω ανώνυμη κλάση.
 +
 +<code cpp lamda2functor.cpp>
 +class __lambda_unique_name {
 +private:
 +    int& sum;           // Capture by reference
 +    int& count;         // Capture by reference
 +    const int threshold; // Capture by value
 +
 +public:
 +    // Constructor για την αρχικοποίηση των captures
 +    __lambda_unique_name(int& _sum, int& _count, int _threshold) 
 +        : sum(_sum), count(_count), threshold(_threshold) {}
 +
 +    // Ο τελεστής κλήσης (το σώμα της lambda)
 +    // Είναι const εξ ορισμού, εκτός αν χρησιμοποιηθεί η λέξη 'mutable'
 +    void operator()(int g) const {
 +        if (g >= threshold) {
 +            sum += g;
 +            count++;
 +        }
 +    }
 +
 +    // Ο compiler διαγράφει τον default constructor
 +    __lambda_unique_name() = delete;
 +};
 +</code>
 +
 +Παρατηρούμε ότι η μεταβλητή //threshold// δεν αλλάζει μέσα στην έκφραση //lambda//. Αν θέλαμε να αλλάζει σε διαφορετικές κλήσεις, θα έπρεπε να προσθέσουμε τη λέξη //mutable//
 +
 +==== Παράδειγμα 2ο - Αθροιστής ====
 +
 +Ας δούμε το παρακάτω παράδειγμα που απεικόνίζει έναν αθροιστή και μεταβάλει μία μεταβλητή που έχει περαστεί με τιμή στο //Clause//.
 +
 +<code cpp sample_accumulator.cpp>
 +#include <iostream>
 +#include <vector>
 +
 +int main() {
 +    // Το [total = 0] δημιουργεί μια εσωτερική μεταβλητή (capture by value).
 +    auto add_to_total = [total = 0](int amount) mutable {
 +        total += amount; // Η τροποποίηση επιτρέπεται μόνο λόγω του 'mutable'
 +        return total;
 +    };
 +
 +    std::vector<int> expenses = {10, 45, 5, 20};
 +
 +    std::cout << "Starting accumulation..." << std::endl;
 +    
 +    for (int bill : expenses) {
 +        std::cout << "Adding: " << bill 
 +                  << " | Current Total: " << add_to_total(bill) 
 +                  << std::endl;
 +    }
 +}
 +</code>
 +
 +Στο παράδειγμα, η μεταβλητή ''total'' μεταβάλει την τιμή της σε κάθε κλίση της έκφρασης //lamda//. Εδώ η προσθήκη της λέξης //mutable// είναι απαραίτητη και χωρίς αυτή το πρόγραμμα δεν μεταγλωττίζεται. H λέξη //mutable// σηματοδοτεί ότι η μεταβλητή στο //Capture Clause// μπορεί να αλλάξει τιμή. Ο λόγος που συμβαίνει αυτό είναι γιατί η λέξη //mutable// σηματοδοτεί ότι η συνάρτηση υπερφόρτωσης του τελεστή () δε θα είναι const. Παρακάτω δίνουμε την ανώνυμη κλάση (functor) που παράγεται για τη δεδομένη //lambda// έκφραση.
 +
 +<code cpp lamda2functor2.cpp>
 +class __lambda_accumulator_unique {
 +private:
 +    int total; // Το εσωτερικό state (capture by value)
 +
 +public:
 +    // Constructor που αρχικοποιεί το total (στην περίπτωσή μας με 0)
 +    __lambda_accumulator_unique(int initial_val) : total(initial_val) {}
 +
 +    /**
 +     * Ο operator() ΔΕΝ είναι const. 
 +     * Αυτό συμβαίνει επειδή χρησιμοποιήσαμε τη λέξη 'mutable'.
 +     * Αν έλειπε το 'mutable', η μέθοδος θα ήταν: 
 +     * int operator()(int amount) const { ... } 
 +     * και η γραμμή total += amount θα έβγαζε error στη μεταγλώττιση.
 +     */
 +    int operator()(int amount) {
 +        total += amount; // Τροποποιούμε το data member της κλάσης
 +        return total;
 +    }
 +};
 +</code>
 +
 +==== Παράδειγμα 3ο - Password Cheker ====
 +
 +Παρακάτω δίνεται ένα πρόγραμμα που διαβάζει από ένα std::vector ένα σύνολο από passwords, εφαρμόζει κάποια κριτήρια για τον αν τα passwords είναι valid ή όχι και εκτυπώνει για κάθε passowrd τη θέση του στη λίστα και τόσα αστεράκια όσα είναι το μέγεθος του. Τα κριτήρια για το αν ένα passowrd είναι valid είναι α) μέγεθος τουλάχιστον 8 χαρκτήρες, β) πρέπει να περιέχει τουλάχιστον ένα πεζό, ένα κεφαλαίο, έναν αριθμό και ένα ειδικό χαρακτήρα. 
 +
 +<code cpp password_checker.cpp>
 +#include <iostream>
 +#include <vector>
 +#include <string>
 +#include <algorithm>
 +#include <cctype>
 +
 +//using namespace std;
 +
 +int main() {
 +    // Λίστα με passwords για έλεγχο
 +    std::vector<std::string> passwords = {
 +        "Pass123!",      // Valid
 +        "weak",          // Invalid (μικρό μέγεθος)
 +        "OnlyLetters",   // Invalid (λείπουν αριθμοί/σύμβολα)
 +        "NoSpecial12",   // Invalid (λείπει ειδικός χαρακτήρας)
 +        "Valid_Pass_2026", // Valid
 +        "12345678",      // Invalid (λείπουν γράμματα)
 +        "Ab1!"           // Invalid (πολύ μικρό)
 +    };
 +
 +    // Λάμδα για τον έλεγχο εγκυρότητας
 +    auto isValid = [specialChars = std::string("!@#$%^&*()-_=+[]{}|;:,.<>?/")](const std::string& p) -> bool {
 +        if (p.length() < 8) return false;
 +
 +        bool hasUpper = false, hasLower = false, hasDigit = false, hasSpecial = false;        
 +
 +        for (char c : p) {
 +            if (std::isupper(c)) hasUpper = true;
 +            else if (std::islower(c)) hasLower = true;
 +            else if (std::isdigit(c)) hasDigit = true;
 +            else if (specialChars.find(c) != std::string::npos) hasSpecial = true;
 +        }
 +
 +        return hasUpper && hasLower && hasDigit && hasSpecial;
 +    };
 +
 +    std::cout << "------- Checking Passwords -----------" << std::endl;
 +    std::cout << "Position | Masked Password | Status" << std::endl;
 +    std::cout << "--------------------------------------" << std::endl;
 +
 +    for (size_t i = 0; i < passwords.size(); ++i) {
 +        bool valid = isValid(passwords[i]);
 +        
 +        // Εκτύπωση θέσης (i + 1)
 +        std::cout << "[" << i + 1 << "     ";
 +
 +        // Εκτύπωση αστερίσκων αντί για το password
 +        std::string masked(passwords[i].length(), '*');
 +        std::cout << masked;
 +
 +        // Ευθυγράμμιση εξόδου (padding)
 +        int padding = 15 - (int)passwords[i].length();
 +        for(int j=0; j < (padding > 0 ? padding : 1); ++j) std::cout << " ";
 +
 +        std::cout << "| " << (valid ? "VALID" : "INVALID") << std::endl;
 +    }
 +
 +    return 0;
 +}
 +</code>
 +
 +==== Παράδειγμα 4ο - Μετασχηματισμός ====
 +
 +Ας υποθέσουμε ότι έχουμε ένα //std::vector// από αντικείμενα τύπου Student (βλέπε παρακάτω) και θέλουμε να μετασχήματίσουμε τα αντικείμενα αυτά ώστε να κρατήσουμε μόνο τους φοιτητές με ΑΕΜ από 1000 εως 2000 και το αποτέλεσμα να το εισάγουμε σε ένα νέο //std::vector// ή ένα νέο //std::set//.
 +
 +<code cpp Student.hpp>
 +#ifndef _STUDENT_HPP_
 +#define _STUDENT_HPP_
 +#include <cstring>
 +#include <iostream>
 +
 +class Student {
 +private:
 +  char *name;
 +  int aem;
 +public:
 +  Student();
 +  Student(const char *name, int aem);
 +  Student(const Student& );
 +  ~Student();
 +  
 +  char* getName() const;
 +  int getAEM() const;  
 +  void setName(char*);
 +  void setAEM(int);
 +  
 +  friend std::ostream& operator<<(std::ostream& out, const Student & st);
 +  bool operator>(const Student& st) const;
 +  bool operator<(const Student& st) const;
 +  Student& operator=(const Student& st);
 +};
 +
 +Student::Student(const char *name, int aem) {
 +  this->name = new char [strlen(name) + 1];
 +  strcpy(this->name, name);
 +  this->aem = aem;
 +  std::cerr << "Argu Construct : " << *this << std::endl;
 +}
 +
 +Student::Student(const Student& st) {
 +  name = new char [strlen(st.name) + 1];
 +  strcpy(name, st.name);
 +  aem = st.aem;
 +  std::cerr << "Copy Construct : " << *this << std::endl;
 +}
 +
 +Student::Student() {
 +  this->name = nullptr;
 +  this->aem = 0;
 +}
 +
 +Student::~Student() {
 +  if(name != nullptr) {
 +    std::cerr << "Destruct: " << *this << std::endl;
 +    delete []name;
 +  }
 +}
 +
 +char* Student::getName() const {
 +  return name;
 +}
 +
 +int Student::getAEM() const {
 +  return aem;
 +}
 +
 +void Student::setName(char* name) {
 +  this->name != nullptr;
 +  delete this->name;
 +  this->name = new char [strlen(name) + 1];
 +  strcpy(this->name, name);
 +}
 +
 +void Student::setAEM(int aem) {
 +  this->aem = aem;
 +}
 +
 +Student& Student::operator=(const Student& st) {
 +  if(name != nullptr)
 +    delete name;
 +  name = new char [strlen(st.name) + 1];
 +  strcpy(name, st.name);
 +  aem = st.aem;
 +  std::cerr << "Copy : " << *this << std::endl;
 +  return *this;
 +}
 +
 +std::ostream& operator<<(std::ostream& out, const Student& st) {
 +  if(st.name != nullptr)
 +    out << st.name << " " << st.aem;
 +  return out;
 +}
 +
 +bool Student::operator>(const Student& st) const {
 +  if(aem > st.aem)
 +    return true;
 +  return false;
 +}
 +
 +bool Student::operator<(const Student& st) const {
 +  if(aem < st.aem)
 +    return true;
 +  return false;
 +}
 +#endif
 +</code>
 +
 +<code cpp trasfrorm_vector2vector.cpp>
 +#include <iostream>
 +#include <vector>
 +#include <algorithm> // Για το std::copy_if
 +#include <iterator>  // Για το std::back_inserter
 +#include "Student.hpp"
 +
 +int main() {
 +    // 1. Αρχικό vector με 5 αντικείμενα Student
 +    std::vector<Student> students;
 +    students.push_back(Student("Giannis", 1050));
 +    students.push_back(Student("Maria", 950));
 +    students.push_back(Student("Kostas", 1500));
 +    students.push_back(Student("Eleni", 2500));
 +    students.push_back(Student("Nikos", 1999));
 +
 +    // 3. Το ΝΕΟ vector όπου θα αποθηκευτούν οι φοιτητές που θα "επιζήσουν"
 +    std::vector<Student> filteredStudents;
 +
 +    std::cout << "\n--- Φιλτράρισμα με Lambda σε νέο Vector ---\n" << std::endl;
 +
 +    // 2. Φιλτράρισμα και αποθήκευση στο νέο vector
 +    std::copy_if(students.begin(), students.end(), 
 +                 std::back_inserter(filteredStudents), // Εισαγωγή στο τέλος του νέου vector
 +                 [](const Student& st) {
 +                     return st.getAEM() >= 1000 && st.getAEM() <= 2000;
 +                 });
 +
 +    // Εκτύπωση των αποτελεσμάτων του νέου vector
 +    std::cout << "\n--- Φοιτητές στο Νέο Vector ---" << std::endl;
 +    for (const auto& student : filteredStudents) {
 +        std::cout << student << std::endl;
 +    }
 +    
 +    std::cout << "\n--- Τέλος Προγράμματος ---" << std::endl;
 +    return 0;
 +}
 +</code>
 +
 +<code cpp trasfrorm_vector2set.cpp>
 +#include <iostream>
 +#include <vector>
 +#include <set>
 +#include <algorithm> // Απαραίτητο για το std::copy_if
 +#include <iterator>  // Απαραίτητο για το std::inserter
 +#include "Student.hpp"
 +
 +int main() {
 +    // 1. Δημιουργία vector με 5 αντικείμενα Student
 +    std::vector<Student> students;
 +    students.push_back(Student("Giannis", 1050));
 +    students.push_back(Student("Maria", 950));
 +    students.push_back(Student("Kostas", 1500));
 +    students.push_back(Student("Eleni", 2500));
 +    students.push_back(Student("Nikos", 1999));
 +
 +    // 3. Το set όπου θα αποθηκευτούν οι φοιτητές που θα "επιζήσουν"
 +    std::set<Student> filteredStudents;
 +
 +    std::cout << "\n--- Φιλτράρισμα με Lambda και std::copy_if ---\n" << std::endl;
 +
 +    // 2. Φιλτράρισμα και αποθήκευση ταυτόχρονα
 +    std::copy_if(students.begin(), students.end(), 
 +                 std::inserter(filteredStudents, filteredStudents.end()), 
 +                 [](const Student& st) {
 +                     return st.getAEM() >= 1000 && st.getAEM() <= 2000;
 +                 });
 +
 +    // Εκτύπωση των αποτελεσμάτων
 +    std::cout << "\n--- Φοιτητές στο Set ---" << std::endl;
 +    for (const auto& student : filteredStudents) {
 +        std::cout << student << std::endl;
 +    }
 +    
 +    std::cout << "\n--- Τέλος Προγράμματος ---" << std::endl;
 +    return 0;
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
  
  
cpp/lamdas.1779399202.txt.gz · Last modified: 2026/05/21 21:33 by gthanos