3. Майже гасло Витончені технології призначені для досягнення простоти. ( original : Clever techniques should be applied for the benefit of simplicity. )
4. Що воно таке? Узагальнений функтор – це будь-який виклик процедури, що дозволений в С++ та інкапсульований в об'єкт першого класу, який гарантує типову безпеку generalized functor is any processing invocation that C++ allows, encapsulated as a typesafe first-class object
5. Для чого? Узагальнені функтори дозволяють зберігати виклики процедур у вигляді значень, передавати їх в якості параметрів, і виконувати іх далеко від місця створення. Суттєвою відмінністю між вказівниками на функції та узагальненими функторами в тому, що останні можуть зберігати стан об'єкта та викликати його методи.
6. The Command Design Pattern Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides . 1995. Design Patterns: Elements of Reusable Object-Oriented Software.
7. Що це дає? Модуль, що здійснює виклик не тільки не знає як виконується робота, а й не має уявлення для якого виду роботи призначений клас Command
8.
9.
10. Generalized callback void Foo(); void Bar(); int main() { void (*pF)() = &Foo; Foo(); // Call Foo directly Bar(); // Call Bar directly (*pF)(); // Call Foo via pF void (*pF2)() = pF; // Create a copy of pF pF = &Bar; // Change pF to point to Bar (*pF)(); // Now call Bar via pF (*pF2)(); // Call Foo via pF2 }
11.
12.
13.
14. Виходить без шаблонів ніяк? template < typename ResultType> class Functor { public: ResultType operator ()(); // other member functions private: // implementation };
15. Ну а де аргументи? Ми не маємо морального права накладати обмеження на кількість аргументів operator() ’ а та на їх тип. Крім того змінних шаблонів в С++ немає. А еліпси ( ellipsis ) типу printf – це не красиво, та ще й небезпечно. Що робити?
16. Так теж не годиться // Functor with no arguments template < typename ResultType> class Functor { ... }; // Functor with one argument template < typename ResultType, typename Parm1> class Functor { ... };
17. Списки типів < typename ResultType, class TList> class Functor { ... }; Functor <double, TYPELIST_2 (int, double)> m yFunctor;
18. Але й списки не ідеальні template < typename R> class FunctorImpl<R, NullType> { public: virtual R operator() () = 0; virtual FunctorImpl* Clone() const = 0; virtual ~FunctorImpl() {} }; template < typename R, typename P1> class FunctorImpl<R, TYPELIST_1(P1)>{ public: virtual R operator() (P1) = 0; virtual FunctorImpl* Clone() const = 0; virtual ~FunctorImpl() {} };
21. Реалізація operator() ’ а template < typename R, class TList> class Functor { ... as above ... public: R operator() () { return (*spImpl_)(); } R operator() (Parm1 p1) { return (*spImpl_)(p1); } R operator() (Parm1 p1, Parm2 p2) { return (*spImpl_)(p1, p2); } };
22. В чому фокус? Functor<double, TYPELIST_2(int, double)> myFunctor; double result = myFunctor(4, 5.6); // Wrong invocation. double result = myFunctor();
23.
24. Так багато коду для одного конструктора template < class ParentFunctor, typename Fun> class FunctorHandler : public FunctorImpl < typename ParentFunctor::ResultType, typename ParentFunctor::ParmList > { public : typedef typename ParentFunctor::ResultType ResultType; …