User Tools

Site Tools


cpp:functors

Function Objects ή Functors

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

Η συνάρτηση for_each

Η συνάρτηση std::for_each επιτρέπει την μεταβολή του περιεχομένου ενός container από first έως last (μη συμπεριλαμβανομένου) από τη συνάρτηση fn. Η υλοποίηση της συνάρτησης δίνεται παρακάτω:

template<class InputIterator, class Function>
  Function for_each(InputIterator first, InputIterator last, Function fn) {
  while (first!=last) {
    fn (*first);
    ++first;
  }
  return fn;      // or, since C++11: return move(fn);
}

Παρακάτω δίνεται ένα παράδειγμα, όπου στα περιεχόμενα ενός vector<string> προστίθεται το prefix “light” με τη βοήθεια της συνάρτησης prefixMe:

prefix_str.cpp
#include <vector>
#include <algorithm>
#include <iostream>
 
using namespace std;
 
template<typename T>
void print(vector<T> v) {
  for(auto it = v.cbegin(); it!=v.cend(); it++) 
    cout << *it << ", ";
  cout << endl;
}
 
void prefixMe(string& str) {
  str = "light " + str;
}
 
int main() {
  vector<string> colors;
 
  colors.push_back("red");
  colors.push_back("green");
  colors.push_back("blue");
 
  print(colors);
  for_each(colors.begin(), colors.end(), prefixMe);
  print(colors);
}

Χρήση ενός function object αντί για συνάρτηση

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

  1. διαθέτει ένα πεδίο το οποίο περιέχει το prefix που θα προστεθεί.
  2. υπερφορτώνει τον τελεστή () (operator()) με ένα μόνο όρισμα τύπου std::string, ώστε να μπορούμε να το χρησιμοποιήσουμε ως συνάρτηση.

Ένα τέτοιο αντικείμενο ονομάζεται function object ή functor. Δείτε το παρακάτω παράδειγμα όπου ορίζουμε την κλάση PrefixString, η οποία λαμβάνει στον κατασκευαστή της ένα std::string που θα αποτελέσει το prefix. Με βάση τον παρακάτω κώδικα, χρησιμοποιώντας αντικείμενα της συγκεκριμένης κλάσης ως συναρτήσεις, μπορούμε να καλέσουμε διαφορετικές εκδόσεις της συνάρτησης που προσθέτει το prefix, απλά αλλάζοντας την παράμετρο στον κατασκευαστή της.

prefix_str_function_object.cpp
#include <vector>
#include <algorithm>
#include <iostream>
 
using namespace std;
 
template<typename T>
void print(vector<T> v) {
  for(auto it = v.cbegin(); it!=v.cend(); it++) 
    cout << *it << ", ";
  cout << endl;
}
 
class PrefixString {
  string prefix;
public:
  PrefixString(string p): prefix(p) {}
  void operator()(string& str) {
    str = prefix + str;
  }
};
 
int main() {
  vector<string> colors;
 
  colors.push_back("red");
  colors.push_back("green");
  colors.push_back("blue");
 
  print(colors);
  for_each(colors.begin(), colors.end(), PrefixString("light "));
  print(colors);
}
cpp/functors.txt · Last modified: 2020/06/01 04:25 (external edit)