Слайд 1Generalized FUNCTORS
В рамках курсу “Актуальні проблеми програмної інженерії”, 2009 р.
Лозинський Ігор,
Фін-3
Слайд 2Ги-ги…
Додаткова інформація:
В презентації 32 сторінки
Наперед
перепрошую за всі лажі та недопрацювання.
☺
Слайд 3Майже гасло
“Особливо розумні” технології призначені для досягнення простоти.
(original: Clever techniques should
be applied for the benefit of simplicity. )
Слайд 4Актуальні проблеми прогамної інженерії :: generalized functors
Що воно таке?
Узагальнений функтор –
це будь-який виклик процедури, що дозволений в С++ та інкапсульований в об'єкт першого класу, який гарантує типову безпеку
generalized functor is any processing invocation that C++ allows, encapsulated as a typesafe first-class object
Слайд 5Актуальні проблеми прогамної інженерії :: generalized functors
Для чого?
Узагальнені функтори дозволяють зберігати
виклики процедур у вигляді значень, передавати їх в якості параметрів, і виконувати іх далеко від місця створення. Суттєвою відмінністю між вказівниками на функції та узагальненими функторами в тому, що останні можуть зберігати стан об'єкта та викликати його методи.
Слайд 6Актуальні проблеми прогамної інженерії :: generalized functors
The Command Design Pattern
Gamma, Erich,
Richard Helm, Ralph Johnson, and John Vlissides . 1995. Design Patterns: Elements of Reusable Object-Oriented Software.
Слайд 7Актуальні проблеми прогамної інженерії :: generalized functors
Що це дає?
Модуль, що здійснює
виклик не тільки не знає як виконується робота, а й не має уявлення для якого виду роботи призначений клас Command
Слайд 8Актуальні проблеми прогамної інженерії :: generalized functors
Застосування
// 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
Слайд 9Актуальні проблеми прогамної інженерії :: generalized functors
В реальному житті
Розробка інтерфейсів користувача
окремо від самих програм (skinnable)
Оболонки не мають архітектури, вони лише надають місця для об'єктів класу Command
Слайд 10Актуальні проблеми прогамної інженерії :: generalized functors
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Актуальні проблеми прогамної інженерії :: generalized functors
Ті, що підтримують operator() (callable)
Функції
Вказівники
на функції
Відсилки на функції (константні вказівники)
Функтори (об'єкти, в яких визначений operator() )
Результати застосування операторів .* та ->* до указників на функції-члени.
Слайд 12Актуальні проблеми прогамної інженерії :: generalized functors
Скелет Functor’а
Клас Functor має поліморфну
реалізацію, але це сховано всередині нього.
Реалізація базового класу - FunctorImpl
Слайд 13Актуальні проблеми прогамної інженерії :: generalized functors
Починаємо реалізовувати
Перша реалізація – перша
проблема
class Functor {
public: void operator()();
// other member functions
private:
// implementation goes here
};
Слайд 14Актуальні проблеми прогамної інженерії :: generalized functors
Виходить без шаблонів ніяк?
template
ResultType>
class Functor {
public:
ResultType operator()();
// other member functions
private:
// implementation
};
Слайд 15Актуальні проблеми прогамної інженерії :: generalized functors
Ну а де аргументи?
Ми не
маємо морального права накладати обмеження на кількість аргументів operator()’а та на їх тип.
Крім того змінних шаблонів в С++ немає.
А еліпси (ellipsis) типу printf – це не красиво, та ще й небезпечно.
Що робити?
Слайд 16Актуальні проблеми прогамної інженерії :: generalized functors
Так теж не годиться
// Functor
with no arguments template
class Functor { ... };
// Functor with one argument template
class Functor { ... };
Слайд 17Актуальні проблеми прогамної інженерії :: generalized functors
Списки типів ☺
TList>
class Functor { ... };
Functor myFunctor;
Слайд 18Актуальні проблеми прогамної інженерії :: generalized functors
Але й списки не ідеальні
template
class FunctorImpl {
public: virtual R operator()() = 0;
virtual FunctorImpl* Clone() const = 0;
virtual ~FunctorImpl() {}
};
template
class FunctorImpl{
public: virtual R operator()(P1) = 0;
virtual FunctorImpl* Clone() const = 0;
virtual ~FunctorImpl() {}
};
Слайд 19Актуальні проблеми прогамної інженерії :: generalized functors
Сам пан Functor
template
class TList>
class Functor {
public:
Functor();
Functor(const Functor&);
Functor& operator=(const Functor&);
explicit Functor(std::auto_ptr spImpl);
...
private:
FunctorImpl Impl;
std::auto_ptr spImpl_;
};
Слайд 20Актуальні проблеми прогамної інженерії :: generalized functors
Маленька хитрість
template
TList>
class Functor {
typedef TList ParmList;
typedef typename TypeAtNonStrict::Result Parm1;
typedef typename TypeAtNonStrict::Result Parm2;
... as above ...
};
Доступаємось до типу, знаючи його номер (дивно, але працює ☺ )
Слайд 21Актуальні проблеми прогамної інженерії :: generalized functors
Реалізація operator()’а
template
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Актуальні проблеми прогамної інженерії :: generalized functors
В чому фокус?
Functor
myFunctor;
double result = myFunctor(4, 5.6);
// Wrong invocation.
double result = myFunctor();
Слайд 23Актуальні проблеми прогамної інженерії :: generalized functors
Робота з функторами
template
class TList>
class Functor {
... as above ...
public:
template
Functor(const Fun& fun);
};
Таким чином ми доступатимемось до інших функторів
Слайд 24Актуальні проблеми прогамної інженерії :: generalized functors
Так багато коду для одного
конструктора
template
class FunctorHandler : public FunctorImpl
<
typename ParentFunctor::ResultType,
typename ParentFunctor::ParmList
>
{
public:
typedef typename ParentFunctor::ResultType ResultType;
…
Слайд 25Актуальні проблеми прогамної інженерії :: generalized functors
… готуємо конструктор
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_;
};
Слайд 26Актуальні проблеми прогамної інженерії :: generalized functors
Нарешті вимучили наш конструктор
template
R, class TList>
template
Functor::Functor(const Fun& fun) :
spImpl_(new FunctorHandler(fun));
{ }
Ще один трюк – шаблонне визначення члена поза межами класу
("out-of-class member template definition." )
Слайд 27Актуальні проблеми прогамної інженерії :: generalized functors
Тестуємо – все красиво
#include “Functor.h”
#include
struct TestFunctor {
void operator()(int i, double d) {
cout <<"TestFunctor::operator()(" << i << ", " << d << ") called.\n"; }
};
int main() {
TestFunctor f;
Functor cmd(f);
cmd(4, 4.5);
}
Слайд 28Актуальні проблеми прогамної інженерії :: generalized functors
Не просто красиво – дуже
красиво
Працюємо з функторами
Працюємо з функціями
Автоматично зводимо типи аргументів та результатів (все й справді чесно) (приклад: char* -> string)
Слайд 29Актуальні проблеми прогамної інженерії :: generalized functors
Вказівники на методи об'єктів
Є певні
нюанси (але вони дещо виходять за межі нашого обговорення, та й для чого ускладнювати?)
Реалізується тим же шляхом що й FunctorHandler
Слайд 30Актуальні проблеми прогамної інженерії :: generalized functors
Бонуси
Зв'язування певних атрибутів (до початку
виклику ми не тільки вкажемо на виконавця, але й задамо атрибути виконання, тобто певне описання середовища, в якому відбувається робота ).
Ланцюжок – (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.
Слайд 31Актуальні проблеми прогамної інженерії :: generalized functors
Де це знайти?
loki
Посилання:
http://sourceforge.net/projects/loki-lib
Для презентації
використовувалась версія 0.1.7
Слайд 32Актуальні проблеми прогамної інженерії :: generalized functors
Ніби кінець…
Спасибі за увагу
Буду
вдячний, якщо питання Ви не задаватимете. ☺