Upload
ppd1961
View
7.881
Download
1
Tags:
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
March 06, 2008
Generalized Functors
Dr. Partha Pratim DasInterra Systems (India) Pvt. Ltd.
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
05-Mar-08 3
Design Patterns
GoF BasicsGoF Basics
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.
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.
05-Mar-08 6
Sample Design Patterns
Creational Structural Behavioral
Abstract Factory Composite Command
Singleton Proxy Iterator
Visitor
05-Mar-08 7
Command Design Pattern
The World of DelegationThe World of Delegation
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.
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.
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
05-Mar-08 11
Command Pattern
• Motivation
05-Mar-08 12
Command Pattern
• Motivation
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
05-Mar-08 14
Command Pattern
• Structure
• Interface Separation• Time Separation
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.
05-Mar-08 16
Command Pattern
• Collaborations
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
05-Mar-08 18
Command Pattern
Macro / Composite Command
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.
05-Mar-08 20
Command Pattern: Request-in-Object
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
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().
05-Mar-08 23
Sample Command Pattern Usage
05-Mar-08 24
Sample Command Pattern Usage
05-Mar-08 25
Sample Command Pattern Usage
05-Mar-08 26
Sample Command Pattern Usage
05-Mar-08 27
Sample Command Pattern Usage
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
05-Mar-08 29
How to Implement Command Pattern?
• Function Pointers?• Functors?• Generalized Functors?
05-Mar-08 30
Function Pointers
RecapRecap
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
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
05-Mar-08 33
Function Pointers
• Programming Techniques for– Replacing switch/if-statements, – Realizing user-defined late-binding or – Implementing callbacks.
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}
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);}
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()
}
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);
}
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
05-Mar-08 39
Functors
Function Objects in C++Function Objects 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.
05-Mar-08 41
Basic Functor
• Any class that overloads the function call operator:– void operator()();– int operator()(int, int);– double operator()(int, double);– ...
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);
}
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);
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());
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;
05-Mar-08 46
Generalized Functors
Basic NotionsBasic Notions
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.
05-Mar-08 48
Generalized Functors
• Implementation– Handle-Body (PIMPL) Idiom
class Functor { public:
void operator()(); // other member functions
private: // implementation goes hereFunctorImpl *pImpl_;
};
05-Mar-08 49
Generalized Functors• Parameterized Return Values
template <typename ResultType> class Functor { public:
ResultType operator()(); // other member functions
private: // implementation
};
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 { ... };
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;
}
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
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
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;
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 };};
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;
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(...) ...
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() {}
};
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() {}
};
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_;
};
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); } };
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.
05-Mar-08 63
Using Functor
• Work by yourself
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
05-Mar-08 65
Thank You