Oggetti funzione (1) In C++ è possibile ridefinire l operatore di chiamata a funzione operator() valore_di_ritorno operator() (lista_argomenti); Un oggetto funzione è l istanza di una classe per la quale è stato ridefinito l operatore di chiamata a funzione Gli oggetti funzione generalizzano i puntatori a funzione A differenza dei puntatori a funzione un oggetto funzione può incapsulare dei dati e quindi avere uno stato Laboratorio di Informatica Antonio Monteleone 177
Oggetti funzione (2) template <class T> class Matrix public: Matrix(int rowcount, int colcount) : m_rowcount(rowcount), m_colcount(colcount), m_items(new T[m_rowCount*m_colCount]) fill(m_items, m_items + m_rowcount*m_colcount, T()); ~Matrix delete [] m_items; T & operator() (int i, int j) // oggetto funzione return m_items[i*m_colcount+j]; // altri metodi private: int m_rowcount; int m_colcount; T *m_items; ; template <class T> T trace(const Matrix<T> &M) assert(m.rowcount() == M.colCount()); T val; for (int i=0;i<m.rowcount(); ++i) val += M(i,i); return val; Laboratorio di Informatica Antonio Monteleone 178
Algoritmi generici su contenitori: for_each E possibile scrivere algoritmi generici (funzioni template) applicabili alle classi contenitore che forniscono iteratori appropriati namespace labinfo // Applica f a tutti gli elementi del container template<typename InputIter, typename UnaryFun> UnaryFun for_each(inputiter first, InputIter last, UnaryFun f) for ( ; first!= last; ++first) f(*first); return f; Laboratorio di Informatica Antonio Monteleone 179
Algoritmi generici su contenitori: count // conta tutti gli elementi uguali a value template<typename InputIter, typename EqCmparable> int count(inputiter first, InputIter last, const EqCmparable & value) int acc=0; for ( ; first!= last; ++first) if (*first == value) ++acc; return acc; Laboratorio di Informatica Antonio Monteleone 180
Algoritmi generici su contenitori: count_if // conta tutti gli elementi che soddisfano il // predicato p template<typename InputIter, typename Predicate> int count_if(inputiter first, InputIter last, Predicate p) int acc=0; for ( ; first!= last; ++first) if (p(*first)) ++acc; return acc; Laboratorio di Informatica Antonio Monteleone 181
Algoritmi generici su contenitori: transform // trasforma la sequenza [first, last) mediante // l applicazione della funzione unaria f // il risultato della trasformazione è inserito // nella sequenza iterata da result template <typename InputIter, typename OutputIter, typename UnaryFunction> OutputIter transform(inputiter first, InputIter last, OutputIter result, UnaryFunction f) for ( ; first!= last; ++first, ++result) *result = f(*first); return result; Laboratorio di Informatica Antonio Monteleone 182
Algoritmi generici su contenitori: sort template <typename T> void swap(t&a, T&b) T tmp = a; a = b; b = tmp; // Ordina la sequenza [first, last) template <typename RandomIter> void sort(randomiter first, RandomIter last) ++first; for ( ; first!= last; ++first) for (RandomIter j = last-1; j>first-1; --j) if ((*j) < (*(j-1))) swap(*j, *(j-1)); Laboratorio di Informatica Antonio Monteleone 183
Algoritmi generici su contenitori: sort // Ordina la sequenza [first, last) utilizzando // il predicato binario comp per il confronto template <typename RandomIter, typename LessThanFunctor> void sort(randomiter first, RandomIter last, LessThanFunctor comp) ++first; for ( ; first!= last; ++first) for (RandomIter j = last-1; j>first-1; --j) if (comp(*j, (*(j-1)))) swap(*j, *(j-1)); // namespace labinfo Laboratorio di Informatica Antonio Monteleone 184
Algoritmi generici su contenitori: un esempio d uso class Student public: Student(const string &lname, const string &fname, const string &id) : m_lname(lname), m_fname(fname), m_id(id) string getlastname() const return m_lname; string getfirstname() const return m_fname; string getid() const return m_id; friend ostream & operator<<(ostream &, const Student &); private: string m_lname; string m_fname; string m_id; ; Laboratorio di Informatica Antonio Monteleone 185
Algoritmi generici su contenitori: un esempio d uso using namespace labinfo; void main() Student *students[6]; typedef Student Stdt; students[0] = new Stdt ("Rossi", "Mario", "72"); students[1] = new Stdt ("Bianchi", "Enrico","93"); students[2] = new Stdt("Neri", "Luca", "82"); students[3] = new Stdt ("Rossi","Aldo", "22"); students[4] = new Stdt ("Neri","Ugo", "62"); students[5] = new Stdt ("Rossi","Carlo", "12"); int size = 6; // stampa a video l'elenco di studenti for_each(students, students+size, printstudent); cout << endl; Laboratorio di Informatica Antonio Monteleone 186
Algoritmi generici su contenitori: un esempio d uso // conta gli studenti di cognome "Rossi": funzione pura int c = count_if(students, students+size, isrossi); // conta gli studenti di cognome "Neri": oggetto funzione c = count_if(students, students+size, MatchesLastName("Neri")); // ordina per cognome e stampa a video // L'uso del funtore lessthanbylastname è // necessario poichè si ha a che fare con una // sequenza di puntatori a Student. // Se avessi scritto sort(students, students+size) // la sequenza sarebbe stata ordinata rispetto al valore // dei puntatori e non rispetto al cognome di Student sort(students, students+size, lessthanbylastname); for_each(students, students+size, printstudent); for_each(students, students+size, deletestudent); Laboratorio di Informatica Antonio Monteleone 187
Algoritmi generici su contenitori: un esempio d uso void printstudent(const Student *student) cout << *student << endl; void deletestudent(const Student *student) delete student; bool isrossi(const Student *student) return student->getlastname() == "Rossi"; Laboratorio di Informatica Antonio Monteleone 188
Algoritmi generici su contenitori: un esempio d uso class MatchesLastName // oggetto funzione public: MatchesLastName(const string &lname) : m_lname(lname) bool operator()(const Student *student) return student->getlastname() == m_lname; private: string m_lname; ; bool lessthanbylastname(const Student *s1, const Student *s2) return s1->getlastname() < s2->getlastname(); Laboratorio di Informatica Antonio Monteleone 189
Algoritmi generici su contenitori -- template <typename BidirectionalIter> void reverse(bidirectionaliter first, BidirectionalIter last) while (true) if (first == last first == --last) return; else swap(*first++, *last); -- template <typename RandomIter> void reverse2(randomiter first, RandomIter last) for ( ; first < last; ++first) swap(*first, *--last); Laboratorio di Informatica Antonio Monteleone 190
Algoritmi generici su contenitori -- template <typename InputIter> inline int distance(inputiter first, InputIter last) int d = 0; while (first++ < last) ++d; return d; -- template <typename InputIter, typename Distance> inline void advance(inputiter &i, Distance n) while (n--) ++i; Laboratorio di Informatica Antonio Monteleone 191
Algoritmi generici su contenitori -- template <typename ForwardIter, typename T> inline ForwardIter lower_bound(forwarditer first, ForwardIter last, const T &val) int len = distance(first, last); while (len > 0) int half = len >> 1; ForwardIter middle =first; advance(middle, half); if (*middle < val) first = middle; ++first; len = len - half - 1; else len = half; return first; Laboratorio di Informatica Antonio Monteleone 192
Algoritmi generici su contenitori -- template <typename ForwardIter, typename T> inline bool binary_search(forwarditer first, ForwardIter last, const T &val) ForwardIter i = lower_bound(first, last, val); return i!= last &&!(val < *i); Laboratorio di Informatica Antonio Monteleone 193