General Functors
Upcoming SlideShare
Loading in...5
×
 

General Functors

on

  • 645 views

 

Statistics

Views

Total Views
645
Views on SlideShare
645
Embed Views
0

Actions

Likes
0
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

General Functors                                                                                                                General Functors Presentation Transcript

  • Generalized FUNCTORS В рамках курсу “Актуальні проблеми програмної інженерії”, 2009 р. Лозинський Ігор, Фін-3
  • Ги-ги…
    • Додаткова інформація:
    • В презентації 32 сторінки
    • Наперед перепрошую за всі лажі та недопрацювання.
  • Майже гасло
    • “ Особливо розумні” технології призначені для досягнення простоти.
    • ( original : Clever techniques should be applied for the benefit of simplicity. )
  • Що воно таке?
    • Узагальнений функтор – це будь-який виклик процедури, що дозволений в С++ та інкапсульований в об'єкт першого класу, який гарантує типову безпеку
    • generalized functor is any processing invocation that C++ allows, encapsulated as a typesafe first-class object
  • Для чого?
    • Узагальнені функтори дозволяють зберігати виклики процедур у вигляді значень, передавати їх в якості параметрів, і виконувати іх далеко від місця створення. Суттєвою відмінністю між вказівниками на функції та узагальненими функторами в тому, що останні можуть зберігати стан об'єкта та викликати його методи.
  • The Command Design Pattern
    • Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides . 1995. Design Patterns: Elements of Reusable Object-Oriented Software.
  • Що це дає?
    • Модуль, що здійснює виклик не тільки не знає як виконується робота, а й не має уявлення для якого виду роботи призначений клас Command
  • Застосування
    • // Resize the window
    • window.Resize(0, 0, 200, 100);
    • Command resizeCmd(
    • window, // Object
    • &Window::Resize, // Member function
    • 0, 0, 200, 100); // Arguments
    • // Later on...
    • resizeCmd.Execute(); // Resize the window
  • В реальному житті
    • Розробка інтерфейсів користувача окремо від самих програм ( skinnable )
    • Оболонки не мають архітектури, вони лише надають місця для об'єктів класу Command
  • 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
    • }
  • Ті, що підтримують operator() ( callable )
    • Функції
    • Вказівники на функції
    • Відсилки на функції (константні вказівники)
    • Функтори (об'єкти, в яких визначений operator() )
    • Результати застосування операторів .* та ->* до указників на функції-члени.
  • Скелет Functor ’ а
    • Клас Functor має поліморфну реалізацію, але це сховано всередині нього.
    • Реалізація базового класу - FunctorImpl
  • Починаємо реалізовувати
    • Перша реалізація – перша проблема
    • class Functor {
    • public: void operator ()();
    • // other member functions
    • private:
    • // implementation goes here
    • };
  • Виходить без шаблонів ніяк?
    • template < typename ResultType>
    • class Functor {
    • public:
    • ResultType operator ()();
    • // other member functions
    • private:
    • // implementation
    • };
  • Ну а де аргументи?
    • Ми не маємо морального права накладати обмеження на кількість аргументів operator() ’ а та на їх тип.
    • Крім того змінних шаблонів в С++ немає.
    • А еліпси ( ellipsis ) типу printf – це не красиво, та ще й небезпечно.
    • Що робити?
  • Так теж не годиться
    • // Functor with no arguments template
    • < typename ResultType>
    • class Functor { ... };
    • // Functor with one argument template
    • < typename ResultType, typename Parm1>
    • class Functor { ... };
  • Списки типів 
    • < typename ResultType, class TList>
    • class Functor { ... };
    • Functor <double, TYPELIST_2 (int, double)> m yFunctor;
  • Але й списки не ідеальні
    • 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() {}
    • };
  • Сам пан Functor
    • template < typename R, class TList>
    • class Functor {
    • public:
    • Functor();
    • Functor( const Functor&);
    • Functor& operator=( const Functor&);
    • explicit Functor( std::auto_ptr <Impl> spImpl);
    • ...
    • private:
    • FunctorImpl<R, TList> Impl;
    • std::auto_ptr <Impl> spImpl_;
    • };
  • Маленька хитрість
    • template < typename R, class TList>
    • class Functor {
    • typedef TList ParmList;
    • typedef typename TypeAtNonStrict<TList, 0, EmptyType>::Result Parm1;
    • typedef typename TypeAtNonStrict<TList, 1, EmptyType>::Result Parm2;
    • ... as above ...
    • };
    • Доступаємось до типу, знаючи його номер (дивно, але працює  )
  • Реалізація 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); }
    • };
  • В чому фокус?
    • Functor<double, TYPELIST_2(int, double)> myFunctor;
    • double result = myFunctor(4, 5.6);
    • // Wrong invocation.
    • double result = myFunctor();
  • Робота з функторами
    • template < typename R, class TList>
    • class Functor {
    • ... as above ...
    • public :
    • template < class Fun>
    • Functor( const Fun& fun);
    • };
    • Таким чином ми доступатимемось до інших функторів
  • Так багато коду для одного конструктора
    • template < class ParentFunctor, typename Fun>
    • class FunctorHandler : public FunctorImpl
    • <
    • typename ParentFunctor::ResultType,
    • typename ParentFunctor::ParmList
    • >
    • {
    • public :
    • typedef typename ParentFunctor::ResultType ResultType;
  • … готуємо конструктор
    • FunctorHandler( const Fun& fun) : fun_(fun) {}
    • FunctorHandler* Clone() const {
    • return new FunctorHandler(*this); }
    • ResultType operator() () { return fun_(); }
    • ResultType operator() ( typename ParentFunctor::Parm1 p1) {
    • return fun_(p1); }
    • ResultType operator() ( typename ParentFunctor::Parm1 p1, typename ParentFunctor::Parm2 p2){
    • return fun_(p1, p2); }
    • private:
    • Fun fun_ ;
    • };
  • Нарешті вимучили наш конструктор
    • template < typename R, class TList>
    • template < typename Fun>
    • Functor<R, TList>::Functor( const Fun& fun) :
    • spImpl_( new FunctorHandler<Functor, Fun>(fun));
    • { }
    • Ще один трюк – шаблонне визначення члена поза межами класу
    • ( &quot;out-of-class member template definition.&quot; )
  • Тестуємо – все красиво
    • #include “ Functor.h ”
    • #include <iostream>
    • struct TestFunctor {
    • void operator() (int i, double d) {
    • cout <<&quot;TestFunctor::operator()(&quot; << i << &quot;, &quot; << d << &quot;) called. &quot;; }
    • };
    • int main() {
    • TestFunctor f;
    • Functor<void, TYPELIST_2(int, double)> cmd(f);
    • cmd(4, 4.5);
    • }
  • Не просто красиво – дуже красиво
    • Працюємо з функторами
    • Працюємо з функціями
    • Автоматично зводимо типи аргументів та результатів (все й справді чесно) (приклад: char* -> string )
  • Вказівники на методи об'єктів
    • Є певні нюанси (але вони дещо виходять за межі нашого обговорення, та й для чого ускладнювати?)
    • Реалізується тим же шляхом що й FunctorHandler
  • Бонуси
    • Зв'язування певних атрибутів (до початку виклику ми не тільки вкажемо на виконавця, але й задамо атрибути виконання, тобто певне описання середовища, в якому відбувається робота ).
    • Ланцюжок – ( MacroCommand , з Gamma et al* , 1995 ) - дозволяє створювати пакет виконання команд. Всі команди на момент “запаковування” повинні бути зв'язаними. Проте пізніше однією командою можна запустити цілу програму, створену на етапі виконання.
    • * Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides . 1995. Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley.
  • Де це знайти?
    • loki
    • Посилання:
    • http://sourceforge.net/projects/loki-lib
    • Для презентації використовувалась версія 0.1.7
  • Ніби кінець…
    • Спасибі за увагу
    • Буду вдячний, якщо питання Ви не задаватимете. 