32
Generalized FUNCTORS В рамках курсу “Актуальні проблеми програмної інженерії”, 2009 р. Лозинський Ігор, Фін-3

General Functors

Embed Size (px)

Citation preview

Page 1: General Functors

Generalized FUNCTORS

В рамках курсу “Актуальні проблеми програмної інженерії”, 2009 р.

Лозинський Ігор, Фін-3

Page 2: General Functors

Ги-ги…

Додаткова інформація:

В презентації 32 сторінки

Наперед перепрошую за всі лажі та недопрацювання.

Page 3: General Functors

Майже гасло

Витончені технології призначені для досягнення простоти.

(original: Clever techniques should be applied for the benefit of simplicity. )

Page 4: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

4

Що воно таке?

Узагальнений функтор – це будь-який виклик процедури, що дозволений в С++ та інкапсульований в об'єкт першого класу, який гарантує типову безпеку

generalized functor is any processing invocation that C++ allows, encapsulated as a typesafe first-class object

Page 5: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

5

Для чого?Узагальнені функтори дозволяють зберігати виклики процедур у вигляді значень, передавати їх в якості параметрів, і виконувати іх далеко від місця створення. Суттєвою відмінністю між вказівниками на функції та узагальненими функторами в тому, що останні можуть зберігати стан об'єкта та викликати його методи.

Page 6: General Functors

Актуальні проблеми прогамної інженерії :: 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.

Page 7: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

7

Що це дає?

Модуль, що здійснює виклик не тільки не знає як виконується робота, а й не має уявлення для якого виду роботи призначений клас Command

Page 8: General Functors

Актуальні проблеми прогамної інженерії :: 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

Page 9: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

9

В реальному житті

• Розробка інтерфейсів користувача окремо від самих програм (skinnable)

Оболонки не мають архітектури, вони лише надають місця для об'єктів класу Command

Page 10: General Functors

Актуальні проблеми прогамної інженерії :: 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}

Page 11: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

11

Ті, що підтримують operator() (callable)

• Функції• Вказівники на функції• Відсилки на функції (константні вказівники)• Функтори (об'єкти, в яких визначений

operator() )• Результати застосування операторів .* та ->*

до указників на функції-члени.

Page 12: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

12

Скелет Functor’а

• Клас Functor має поліморфну реалізацію, але це сховано всередині нього.

• Реалізація базового класу - FunctorImpl

Page 13: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

13

Починаємо реалізовувати

• Перша реалізація – перша проблема

class Functor {

public: void operator()();

// other member functions

private:

// implementation goes here

};

Page 14: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

14

Виходить без шаблонів ніяк?

template <typename ResultType>

class Functor {

public:

ResultType operator()();

// other member functions

private:

// implementation

};

Page 15: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

15

Ну а де аргументи?

Ми не маємо морального права накладати обмеження на кількість аргументів operator()’а та на їх тип.

Крім того змінних шаблонів в С++ немає.

А еліпси (ellipsis) типу printf – це не красиво, та ще й небезпечно.

Що робити?

Page 16: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

16

Так теж не годиться

// Functor with no arguments template

<typename ResultType>

class Functor { ... };

// Functor with one argument template

<typename ResultType, typename Parm1>

class Functor { ... };

Page 17: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

17

Списки типів

<typename ResultType, class TList>

class Functor { ... };

Functor<double, TYPELIST_2(int, double)> myFunctor;

Page 18: General Functors

Актуальні проблеми прогамної інженерії :: 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() {}

};

Page 19: General Functors

Актуальні проблеми прогамної інженерії :: 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_;

};

Page 20: General Functors

Актуальні проблеми прогамної інженерії :: 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 ...

};

• Доступаємось до типу, знаючи його номер (дивно, але працює )

Page 21: General Functors

Актуальні проблеми прогамної інженерії :: 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); }

};

Page 22: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

22

В чому фокус?

Functor<double, TYPELIST_2(int, double)> myFunctor;

double result = myFunctor(4, 5.6);

// Wrong invocation.

double result = myFunctor();

Page 23: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

23

Робота з функторами

template <typename R, class TList>

class Functor {

... as above ...

public:

template <class Fun>

Functor(const Fun& fun);

};

• Таким чином ми доступатимемось до інших функторів

Page 24: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

24

Так багато коду для одного конструктора

template <class ParentFunctor, typename Fun>

class FunctorHandler : public FunctorImpl

<

typename ParentFunctor::ResultType,

typename ParentFunctor::ParmList

>

{

public:

typedef typename ParentFunctor::ResultType ResultType;

Page 25: General Functors

Актуальні проблеми прогамної інженерії :: 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_;

};

Page 26: General Functors

Актуальні проблеми прогамної інженерії :: 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." )

Page 27: General Functors

Актуальні проблеми прогамної інженерії :: 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);

}

Page 28: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

28

Не просто красиво – дуже красиво

• Працюємо з функторами

• Працюємо з функціями

• Автоматично зводимо типи аргументів та результатів (все й справді чесно) (приклад: char* -> string)

Page 29: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

29

Вказівники на методи об'єктів

• Є певні нюанси (але вони дещо виходять за межі нашого обговорення, та й для чого ускладнювати?)

• Реалізується тим же шляхом що й FunctorHandler

Page 30: General Functors

Актуальні проблеми прогамної інженерії :: 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.

Page 31: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

31

Де це знайти?

• loki

• Посилання:

http://sourceforge.net/projects/loki-lib

• Для презентації використовувалась версія 0.1.7

Page 32: General Functors

Актуальні проблеми прогамної інженерії :: generalized functors

32

Ніби кінець…

• Спасибі за увагу

• Буду вдячний, якщо питання Ви не задаватимете.