generalized functors - realizing command design pattern in c++
DESCRIPTION
This is from my series of lectures on C++ and Design Patterns at Interra. This was first presented in 2008TRANSCRIPT
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