65
March 06, 2008 Generalized Functors Dr. Partha Pratim Das Interra Systems (India) Pvt. Ltd. Realizing Command Design Pattern in C++

Generalized Functors - Realizing Command Design Pattern in C++

  • Upload
    ppd1961

  • View
    7.881

  • Download
    1

Embed Size (px)

DESCRIPTION

This is from my series of lectures on C++ and Design Patterns at Interra. This was first presented in 2008

Citation preview

Page 1: Generalized Functors - Realizing Command Design Pattern in C++

March 06, 2008

Generalized Functors

Dr. Partha Pratim DasInterra Systems (India) Pvt. Ltd.

Realizing Command Design Pattern in C++

Page 2: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 2

Agenda

• Design Patterns: Introduction

• Command Design Pattern

• How to realize Command Pattern in C++– Function Pointers– Functor– Generalized Functors

Page 3: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 3

Design Patterns

GoF BasicsGoF Basics

Page 4: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 4

What is a Design Pattern?

• A Design Pattern – describes a problem that occurs over and over

in software engineering – and then describes the solution in a

sufficiently generic manner as to be applicable in a wide variety of contexts.

Page 5: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 5

Essential Elements of a Design Pattern

1. Pattern Name: Descriptor for a design problem, its solutions, and their consequences.

2. Problem: Where to apply the pattern and its associated context.

3. Solution: Elements that make up the design, their relationships, responsibilities, and collaborations.

4. Consequences: Results and trade-offs in applying the pattern.

Page 6: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 6

Sample Design Patterns

Creational Structural Behavioral

Abstract Factory Composite Command

Singleton Proxy Iterator

Visitor

Page 7: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 7

Command Design Pattern

The World of DelegationThe World of Delegation

Page 8: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 8

“Check @ Diner” – A Command Pattern

• Customer places an Order with Waitress

• Waitress writes Order on check.

• Order is queued to Cook.

Page 9: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 9

“Compose & Send Mail” – A Command Pattern

• Sender composes a Mail with Word and presses “Send”

• Mail is queued on Outbox.

• SendMail thread checks the connection and send the Mails from Outbox.

Page 10: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 10

Command Pattern

• Intent– Encapsulate requests for service from an object

inside other objects to allow manipulation of the requests in various ways

Page 11: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 11

Command Pattern

• Motivation

Page 12: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 12

Command Pattern

• Motivation

Page 13: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 13

Command Pattern

• Applicability– The Command pattern can be used

• To implement a callback function capability

• To specify, queue, & execute requests at different times

• To support undo and change log operations

Page 14: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 14

Command Pattern

• Structure

• Interface Separation• Time Separation

Page 15: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 15

Command Pattern

• Participants– Command

• declares an interface for executing an operation.

– ConcreteCommand (PasteCommand, OpenCommand)• defines a binding between a Receiver object and an action.• implements Execute by invoking the corresponding operation(s) on

Receiver.

– Client (Application)• creates a ConcreteCommand object and sets its receiver.

– Invoker (MenuItem)• asks the command to carry out the request.

– Receiver (Document, Application)• knows how to perform the operations associated with carrying out a

request. Any class may serve as a Receiver.

Page 16: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 16

Command Pattern

• Collaborations

Page 17: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 17

Command Pattern

• Consequences– Command decouples the object that invokes the

operation from the one that knows how to perform it

– Commands are first-class objects. They can be manipulated and extended like any other object.

– Commands can be made into a composite command

Page 18: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 18

Command Pattern

Macro / Composite Command

Page 19: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 19

Command Pattern

• Implementation Issues– How intelligent should a command object be?– Dumb: Delegates the required action to a receiver

object– Smart: Implements everything itself without delegating

to a receiver object at all• Use Functor?

– Active Command: • A functor object usually implements the desired behavior itself

without delegation to another object. – Forwarding Command:

• A command object frequently delegates the desired behavior to another receiver object.

Page 20: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 20

Command Pattern: Request-in-Object

Page 21: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 21

Sample Command Pattern Usage

• Multi-level undo / redo  – The program can keep a pair of stacks of

commands. • Transactional behavior 

– Rollback for all-or-none operations– Installers / Databases. – Two-phase commit.

• Progress bars 

Page 22: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 22

Sample Command Pattern Usage

• Wizards  – What we see

• Several pages of configuration for a single action.• Action fires when the user clicks the "Finish" button.

– What we need• Separate user interface code from application code • Implement the wizard using a command object. • The command class contains no user interface code.

– How it works• Created when the wizard is first displayed. • Each wizard page stores its GUI changes in the command

object.• "Finish" simply triggers a call to execute().

Page 23: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 23

Sample Command Pattern Usage

Page 24: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 24

Sample Command Pattern Usage

Page 25: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 25

Sample Command Pattern Usage

Page 26: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 26

Sample Command Pattern Usage

Page 27: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 27

Sample Command Pattern Usage

Page 28: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 28

Sample Command Pattern Usage

• GUI buttons and menu items  – In Swing and Borland Delphi programming, an Action

is a command object.

• Thread pools / Parallel Processing – Master/Worker pattern

• Macro recording• Command across Network 

– Player actions in computer games.

•   Mobile Code  – Deliver a new behavior to remote locations

Page 29: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 29

How to Implement Command Pattern?

• Function Pointers?• Functors?• Generalized Functors?

Page 30: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 30

Function Pointers

RecapRecap

Page 31: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 31

Function Pointers

• Points to the address of a function– Ordinary C functions– Static C++ member functions– Non-static C++ member functions

• Points to a function with a specific signature– List of Calling Parameter Types– Return-Type – Calling Convention

Page 32: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 32

Function Pointers

• Operations– Assign an Address to a Function Pointer– Compare two Function Pointers– Call a Function using a Function Pointer– Pass a Function Pointer as an Argument– Return a Function Pointer– Arrays of Function Pointers

Page 33: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 33

Function Pointers

• Programming Techniques for– Replacing switch/if-statements, – Realizing user-defined late-binding or – Implementing callbacks.

Page 34: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 34

Function Pointers• Calculator with operators (+, –, *, /) // The four arithmetic operations float Plus (float a, float b) { return a+b; }float Minus (float a, float b) { return a-b; }float Multiply(float a, float b) { return a*b; }float Divide (float a, float b) { return a/b; }

// Solution with a switch-statement void Switch(float a, float b, char opCode) {

float result;switch(opCode) { // execute operation

case ’+’ : result = Plus (a, b); break;case ’-’ : result = Minus (a, b); break;case ’*’ : result = Multiply (a, b); break;case ’/’ : result = Divide (a, b); break;

} cout << "Switch: 2+5=" << result << endl; // display result}

Page 35: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 35

Function Pointers – Replace Switch / IF Statements

One of the four basic Arithmetic Operations - Addition

float Plus (float a, float b) { return a+b; }

void Switch_With_Function_Pointer (float a, float b, float (*pt2Func)(float, float))

{float result = pt2Func(a, b); cout << a << "+" << b << "=" << result << endl;

}

void main(){

Switch_With_Function_Pointer(2, 5, &Plus);}

Page 36: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 36

Function Pointers – Late Binding / Virtual Function

Late Binding is a C++ Feature

class A {public:

void f();virtual void g();

};

class B: public A {public:

void f();virtual void g();

};

void main() {A a;B b;A *p = &b;

a.f(); // A::f()a.g(); // A::g()p->f();// A::f()p->g();// B::g()

}

Page 37: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 37

Function Pointers – Callbacks

Quick Sort Implementation using callback in ‘qsort’

int CmpFunc(const void* a, const void* b) {int ret = (*(const int*)a > *(const int*) b)? 1:

(*(const int*)a == *(const int*) b)? 0: -1;return ret;

}

void main() {int field[10];for(int c=10;c>0;c--)

field[10-c]=c;qsort((void*) field, 10, sizeof(field[0]), CmpFunc);

}

Page 38: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 38

Function Pointers

• Issues– No value semantics– Weak type checking– Two function pointers having identical

signature are necessarily indistinguishable– No encapsulation for parameters

Page 39: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 39

Functors

Function Objects in C++Function Objects in C++

Page 40: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 40

Functors / Closures

• Smart Functions– Functors are functions with a state. – Functors encapsulate C / C++ function pointers

• Uses templates and • Engages polymorphism.

• Has its own Type– A class with

• zero or more private members to store the state and • an overloaded operator() to execute the function.

• Usually faster than ordinary Functions• Can be used to implement callbacks.

Page 41: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 41

Basic Functor

• Any class that overloads the function call operator:– void operator()();– int operator()(int, int);– double operator()(int, double);– ...

Page 42: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 42

Functors: Elementary Exampleint AdderFunction(int a, int b) {

return a + b;}

class AdderFunctor { public:

int operator()(int a, int b) {return a + b;

} };

void main() {int x = 5;int y = 7;int z = AdderFunction(x, y);

AdderFunctor aF;int w = aF(x, y);

}

Page 43: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 43

Functors: Examples from STL

• Fill a vector with random numbers– Function Pointer rand as Function Object

vector<int> V(100); generate(V.begin(), V.end(), rand);

Page 44: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 44

Functors: Examples from STL

• Sort a vector of double by magnitude– User-defined Functor less_mag

struct less_mag: public binary_function<double, double, bool> {

bool operator()(double x, double y) { return fabs(x) < fabs(y); }

};

vector<double> V; ... sort(V.begin(), V.end(), less_mag());

Page 45: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 45

Functors: Examples from STL

• Find the sum of elements in a vector– User-defined Functor adder with local statestruct adder: public

unary_function<double, void> { adder() : sum(0) {} double sum; void operator()(double x) { sum += x; }

};

vector<double> V; ... adder result =

for_each(V.begin(), V.end(), adder()); cout << "The sum is " << result.sum << endl;

Page 46: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 46

Generalized Functors

Basic NotionsBasic Notions

Page 47: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 47

Generalized Functors• Encapsulates any processing invocation• Accepts

– pointers to simple functions, – pointers to member functions, – functors, and – other generalized functors –with some or all of their respective arguments.

• Is typesafe – Never matches the wrong argument types to the wrong functions.

• Is an object with value semantics – Fully supports

• copying, • assignment, and • pass by value.

• A generalized functor can be copied freely and does not expose virtual member functions.

Page 48: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 48

Generalized Functors

• Implementation– Handle-Body (PIMPL) Idiom

class Functor { public:

void operator()(); // other member functions

private: // implementation goes hereFunctorImpl *pImpl_;

};

Page 49: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 49

Generalized Functors• Parameterized Return Values

template <typename ResultType> class Functor { public:

ResultType operator()(); // other member functions

private: // implementation

};

Page 50: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 50

Generalized Functors• No Argument (Generator)

• One Argument (Unary Function)

• Two Arguments (Binary Function)

template <typename ResultType> class Functor { ... };

template <typename ResultType, typename Parm1>

class Functor { ... };

template <typename ResultType, typename Parm1,typename Parm2>

class Functor { ... };

Page 51: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 51

Generalized Functors

• Variable List of Parameters– Variadic Function ellipses not allowed for templates

• Needs a set of Helper Templates• Needs representation for Collection of Types

int VarArgIntSum(int nParam, ...) {va_list va;va_start(va, nParam);for(int i = 0, sum = 0; i < nParam; i++) {

int& val = va_arg(va, int);sum += val;

}va_end(va);return sum;

}

Page 52: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 52

Helper Templates

• NullType– class NullType {};– Not an interesting type.– Marks the end of a typelist and to return "type

not found" information.

• EmptyType– struct EmptyType {};– "don't care" type for a template. – Legal to inherit from

Page 53: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 53

Typelist

• Typelists are a C++ tool for manipulating collections (list) of types.

• Typelist holds two types accessible through the inner names.– Head – Tail

Page 54: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 54

Typelist• Examples

• Generic Listtemplate <class T, class U>struct Typelist{

typedef T Head;typedef U Tail;

};

typedef Typelist<char, Typelist<signed char, unsigned char> > CharList;

typedef Typelist<char, Typelist<signed char,

Typelist<unsigned char, NullType> > > AllCharTypes;

Page 55: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 55

Typelist: Compute Length• Recursion Exit

• Recursion Descend Instantiationtemplate <class T, class U>struct Length< Typelist<T, U> >{

enum { value = 1 + Length<U>::value };};

template <class TList> struct Length;template <> struct Length<NullType>{

enum { value = 0 };};

Page 56: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 56

Typelist: Index a Type• Generic Template

• Recursion Exit

• Recursion Descend Instantiationtemplate <class Head, class Tail, unsigned int i>struct TypeAt<Typelist<Head, Tail>, i>{

typedef typename TypeAt<Tail, i - 1>::Result Result;};

template <class Head, class Tail>struct TypeAt<Typelist<Head, Tail>, 0>{

typedef Head Result;};

template <class Head, class Tail>struct TypeAt;

Page 57: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 57

Typelist: Arbitrary Number of Types

• Iterative Macro Definition

#define TYPELIST_1(T1) \Typelist<T1, NullType>

#define TYPELIST_2(T1, T2) \Typelist<T1, TYPELIST_1(T2) >

#define TYPELIST_3(T1, T2, T3) \Typelist<T1, TYPELIST_2(T2, T3) >

#define TYPELIST_4(T1, T2, T3, T4) \ Typelist<T1, TYPELIST_3(T2, T3, T4) >

//...//#define TYPELIST_50(...) ...

Page 58: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 58

Functor Implementation

template <typename R, class TList> class FunctorImpl;

template <typename R> class FunctorImpl<R, NullType> { public:

virtual R operator()() = 0; virtual FunctorImpl* Clone() const = 0; virtual ~FunctorImpl() {}

};

Page 59: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 59

Functor Implementation

template <typename R, typename P1> class FunctorImpl<R, TYPELIST_1(P1)> { public:

virtual R operator()(P1) = 0; virtual FunctorImpl* Clone() const = 0; virtual ~FunctorImpl() {}

};

template <typename R, typename P1, typename P2> class FunctorImpl<R, TYPELIST_2(P1, P2)> { public:

virtual R operator()(P1, P2) = 0; virtual FunctorImpl* Clone() const = 0; virtual ~FunctorImpl() {}

};

Page 60: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 60

The 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:

// Handy type definition for the body type typedef FunctorImpl<R, TList> Impl; std::auto_ptr<Impl> spImpl_;

};

Page 61: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 61

The Functor: Forwarding Operatortemplate <typename R, class TList> class Functor { ... as above ... typedef TList ParmList; typedef typename

TypeAt<TList, 0, EmptyType>::Result Parm1; typedef typename

TypeAt<TList, 1, EmptyType>::Result Parm2;

public: R operator()()

{ return (*spImpl_)(); } R operator()(Parm1 p1)

{ return (*spImpl_)(p1); } R operator()(Parm1 p1, Parm2 p2)

{ return (*spImpl_)(p1, p2); } };

Page 62: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 62

Using Functor

// Define a Functor that accepts an int and // a double and returns a double. Functor<double, TYPELIST_2(int, double)> myFunctor;

// Invoke it. operator()(double, int) is generated. double result = myFunctor(4, 5.6);

// Wrong invocation. double result = myFunctor(); // error! // operator()() is invalid because // FunctorImpl<double, TYPELIST_2(int, double)> // does not define one.

Page 63: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 63

Using Functor

• Work by yourself

Page 64: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 64

References

• Chapter 5: Generalized Functors in Modern C++ Design: Generic Programming and Design Patterns Applied

– Andrei Alexandrescu• Chapter 22. Function Objects and Callbacks in

C++ Templates: The Complete Guide – David Vandevoorde & Nicolai M. Josuttis

• Chapter 8. STL Function Objects in The C++ Standard Library: A Tutorial and Reference

– Nicolai M. Josuttis• Effective C++ & More Effective C++

– Scott Meyers

Page 65: Generalized Functors - Realizing Command Design Pattern in C++

05-Mar-08 65

Thank You