====== Function Objects ή Functors ======
Συχνά στην STL θέλουμε να εφαρμόσουμε μία συνάρτηση πάνω στο περιεχόμενο ενός //container// προκειμένου να μεταβάλλουμε το περιεχόμενο του ή να αποθηκεύσουμε το αλλαγμένο περιεχόμενο σε ένα διαφορετικό από το αρχικό //container//.
===== Η συνάρτηση for_each =====
Η συνάρτηση [[http://www.cplusplus.com/reference/algorithm/for_each/|std::for_each]] επιτρέπει την μεταβολή του περιεχομένου ενός //container// από //first// έως //last// (μη συμπεριλαμβανομένου) από τη συνάρτηση //fn//. Η υλοποίηση της συνάρτησης δίνεται παρακάτω:
template
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'' προστίθεται το //prefix// "light" με τη βοήθεια της συνάρτησης //prefixMe//:
#include
#include
#include
using namespace std;
template
void print(vector v) {
for(auto it = v.cbegin(); it!=v.cend(); it++)
cout << *it << ", ";
cout << endl;
}
void prefixMe(string& str) {
str = "light " + str;
}
int main() {
vector 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// πρέπει να γράφετε μία νέα συνάρτηση. Αντί για αυτό θα μπορούσαμε να χρησιμοποιήσουμε ένα αντικείμενο ως συνάρτηση το οποίο να έχει τα εξής χαρακτηριστικά:
- διαθέτει ένα πεδίο το οποίο περιέχει το prefix που θα προστεθεί.
- υπερφορτώνει τον τελεστή () (//operator()//) με ένα μόνο όρισμα τύπου //std::string//, ώστε να μπορούμε να το χρησιμοποιήσουμε ως συνάρτηση.
Ένα τέτοιο αντικείμενο ονομάζεται //function object ή functor//. Δείτε το παρακάτω παράδειγμα όπου ορίζουμε την κλάση //PrefixString//, η οποία λαμβάνει στον κατασκευαστή της ένα std::string που θα αποτελέσει το //prefix//. Με βάση τον παρακάτω κώδικα, χρησιμοποιώντας αντικείμενα της συγκεκριμένης κλάσης ως συναρτήσεις, μπορούμε να καλέσουμε διαφορετικές εκδόσεις της συνάρτησης που προσθέτει το //prefix//, απλά αλλάζοντας την παράμετρο στον κατασκευαστή της.
#include
#include
#include
using namespace std;
template
void print(vector 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 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);
}