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