cse 332: c++ stl functors stl functors: functions vs. function objects stl functors support function...
TRANSCRIPT
CSE 332: C++ STL functors
STL Functors: Functions vs. Function Objects
• STL Functors support function call syntax• Algorithms invoke functions and operators
– E.g., calling operator< during a sort algorithm– Those expressions define type requirements– In many cases, can plug in alternative behaviors
• The STL allows diverse functor types– A function pointer (from Lippman, LaJoie, Moo)
bool (*PF) (const string &, const string &) // function ptr type bool *pf (const string &, const string &) // function named pf
– Instance of a class/struct providing operator()– Either one can be invoked (called)
• But may have to deal with signature (and return type)
CSE 332: C++ STL functors
STL Functors Extend STL Algorithms
• Make the algorithms even more general• Can be used parameterize policy
– E.g., the order produced by a sorting algorithm– E.g., the order maintained by an associative container
• Each functor does a single, specific operation– Often implemented as small functions or classes/structs
• E.g., a struct with one public member function, operator()
• Function objects may also have member variables– Arguments not stored may be supplied at point of call– Member variables can parameterize the operation– E.g., the value k for a functor that adds k to another value– E.g., arguments for an invocation on a remote object
CSE 332: C++ STL functors
Function Object Use in an Algorithmstruct GT_magnitude : public
binary_function<double, double, bool> { bool operator() (double x, double y) {
return fabs(y) < fabs(x); }};struct LT_magnitude : public
binary_function<double, double, bool> { bool operator() (double x, double y) {
return fabs(x) < fabs(y); }};
int main (int, char **) {
vector<double> u,v;
for (double d = 0.0;
d < 10.1; d += 1.0){
u.push_back (d);
v.push_back (d);
}
sort (u.begin(), u.end(),
GT_magnitude());
sort (v.begin(), v.end(),
LT_magnitude());
ostream_iterator<double>
o (cout, “ ”));
copy (u.begin(), u.end(), o);
copy (v.begin(), v.end(), o);
return 0;
}
CSE 332: C++ STL functors
Function Use in an Algorithm#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
struct Employee {
Employee (const char * n, int i) : name_(n), id_(i) {}
string name_;
int id_;
};
typedef Employee * EmployeePtr;
ostream& operator<< (ostream & os, const EmployeePtr & e) {
os << e->name_ << " " << e->id_ << " ";
return os;
}
// function for comparing EmployeePtrsbool id_compare (const EmployeePtr & e, const EmployeePtr & f) {
return e->id_< f->id_|| (e->id == f->id && e->name < f->name_);
}
int main (int, char *[]) {
vector<EmployeePtr> v;
v.push_back(new Employee("Claire", 23451));
v.push_back(new Employee("Bob", 12345));
v.push_back(new Employee("Alice", 54321));
cout << "v: " ;
copy (v.begin(), v.end(),
ostream_iterator<EmployeePtr>(cout));
cout << endl;
// "v: Claire 23451 Bob 12345 Alice 54321 "
sort (v.begin(), v.end(), id_compare);
cout << "v: " ;
copy (v.begin(), v.end(),
ostream_iterator<EmployeePtr>(cout));
cout << endl;
// "v: Bob 12345 Claire 23451 Alice 54321 "
// clean up: pointers "own" the heap objects
for (vector<EmployeePtr>::iterator i =
v.begin();
i != v.end(); ++i) {
delete *i;
}
return 0;
}
function name ok here
heap object
CSE 332: C++ STL functors
Function Object Use in a Container#include <set>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
struct Employee {
Employee (const char * n, int i) : name_(n), id_(i) {}
string name_;
int id_;
};
ostream& operator<< (ostream & os, const Employee & e) {
os << e.name_ << " " << e.id_ << “ ";
return os;
}
// set needs this (orders by name then id)
bool operator< (const Employee & e, const Employee & f) {
return e.name_ < f.name_ || (e.name_ == f.name_ && e.id_ < f.id_);
}
// orders by id then name)struct EmployeeIdComp {
bool operator() (const Employee & e, const Employee & f) {
return e.id_ < f.id_ || (e.id_ == f.id_ && e.name_ < f.name_);
}
};
int main (int, char *[]) {
vector<Employee> v;
v.push_back(Employee("Claire", 23451));
v.push_back(Employee("Bob", 12345));
v.push_back(Employee("Alice", 54321));
cout << "v: " ;
copy (v.begin(), v.end(),
ostream_iterator<Employee>(cout));
// "v: Claire 23451 Bob 12345 Alice 54321 "
set<Employee> s;
s.insert(v.begin(), v.end());
cout << "s: " ;
copy (s.begin(), s.end(),
ostream_iterator<Employee>(cout));
// "s: Alice 54321 Bob 12345 Claire 23451 “
set<Employee, EmployeeIdComp> t;
t.insert(v.begin(), v.end());
cout << "t: " ;
copy (t.begin(), t.end(), ostream_iterator<Employee>(cout));
// "t: Bob 12345 Claire 23451 Alice 54321 “
return 0;
}
function object needed
temporary object
CSE 332: C++ STL functors
STL Functor Concepts• Basic Functor Concepts
– Generator– Unary Function– Binary Function
• Adaptable Function Objects (turn functions into function objects)– Adaptable Generator– Adaptable Unary Function– Adaptable Binary Function
• Predicates (return a boolean result)– Predicate– Binary Predicate– Adaptable Predicate– Adaptable Binary Predicate– Strict Weak Ordering
• Specialized Concepts– Random Number Generator– Hash Function
CSE 332: C++ STL functors
STL Functor Concept Hierarchy
Adaptable Function Object
Basic Function Object
Specialized
Predicate
is-refined-byGenerator
UnaryFunction
BinaryFunction
Assignable
AdaptableGenerator
AdaptableUnary
Function
AdaptableBinary
Function
HashFunction
RandomNumber
GeneratorPredicate
AdaptablePredicate
BinaryPredicate
AdaptableBinary
Predicate
StrictWeak
Ordering
CSE 332: C++ STL functors
Assignable Concept
• Does not refine any other STL concept• Valid Expressions
– Copy ConstructorX(x); X x(y); X x = y;
– Assignmentx = y;
• Models of Assignable– Almost every non-const C++ built-in type …– … and function pointers …– … but not functions (cannot construct or assign them)– Here, all Basic Function Object concepts
• Generator, Unary Function, Binary Function• And the concepts that specialize them
CSE 332: C++ STL functors
Generator Concept
• Refines Assignable• Abstracts pointers to 0-ary functions (no arguments)• Valid Expressions
– Function call signature with no arguments f()
• Semantics– Returns some value of type Result– Different invocations may return different values
• Or, can represent a constant as a 0-ary functor
– Invocation may change the function object’s internal state• So, operator() need not be a const member function
CSE 332: C++ STL functors
Generator Example
• Goal: fill a vector with random numbers• Generic generate algorithm
– Fills in a range given in its 1st and 2nd arguments– applies Generator Concept to its 3rd argument
• Here, the functor is simply a function pointer– To the C library’s (0-ary) rand() function
vector<int> v(100); generate(v.begin(), v.end(), rand);
CSE 332: C++ STL functors
Unary Function Concept• Also a refinement of Assignable• Valid Expression
– Function call signature with one argument f(x)
– Semantics• May ignore or use single argument• Similar return, const semantics to generator
• Example - Unary Sine Functor
struct sine : public unary_function<double,double> {
double operator()(double x) const {
return sin(x); }
};
CSE 332: C++ STL functors
Binary Function Concept
• Also a refinement of Assignable• Valid Expression
– Function call signature with two argumentsf(x,y)
– Semantics• May use or ignore either or both of its arguments• Similar const and return semantics to Unary Function
• Example - Exponentiation Functor
struct exponentiate : public binary_function<double,double,double> {
double operator()(double x, double y) const {
return pow(x,y); }
};
CSE 332: C++ STL functors
Adaptable Function Objects• Allow functors to be used with Function Object Adaptors• Associated types – of argument(s), and especially return value• How to access these associated types ?
– Define Adaptable Function Object Concepts • Adaptable Generator
F1::result_type• Adaptable Unary Function
F2::argument_type F2::result_type• Adaptable Binary Function
F3::first_argument_type F3::second_argument_type F3::result_type
• Models– Function pointers like Result(*f)(Arg) do not model these concepts– Helper adapters make Adaptable Function Objects from these functions– For example ptr_fun(f) is a model of Adaptable Unary Function
CSE 332: C++ STL functors
Adaptable Function Object Example• Each value in v2 will be 3.0 larger than the
corresponding element in v1const int N = 1000;
vector<double> v1(N); vector<double> v2(N);
// random valuesgenerate(v1.begin(), v1.end(), rand);
transform(v1.begin(), v1.end(), v2.begin(), bind1st(plus<double>(), 3.0));
Adaptable Function Object
Function Object Adapter (we’ll cover these in a bit)
CSE 332: C++ STL functors
Predicate Concepts• Predicate
– Refinement of Unary Function– Return type must be convertible to bool
• Adaptable Predicate– Refinement of Predicate, Adaptable Unary Function– Adds typedefs for argument, return types
• Binary Predicate– Refinement of Binary Function– Return type again must be convertible to bool
• Adaptable Binary Predicate– Refinement of Binary Predicate, Adaptable Binary Function – Adds typedefs for the 2 arguments, return types
• Strict Weak Ordering– Refinement of Binary Predicate (for comparison operations)– Similar semantics to operator< but with type constraints
CSE 332: C++ STL functors
Random Number Generator
• Refinement of Unary Function– Unfortunately name is similar to Generator (0-ary)
• Valid Expression– Function call
f(N), where N is a positive integer
• Semantics– Returns some value of type Result– Different invocations may return different values– Normal pseudo-random distribution
• If function f is called many times with the same argument N then• Each value in range [0,N) will appear ~ equal number of times
CSE 332: C++ STL functors
Hash Function
• Refinement of Unary Function– Return type must be size_t
• Valid Expression– Function call
f(x)
• Semantics– Map from argument to a size_t result– Equivalent arguments must yield same result– Used by Hashed Associative Containers
CSE 332: C++ STL functors
Function Object Adaptors
• Adaptors transform one interface to another– I.e., they implement the Adapter pattern
• Function Object Adaptors – Perform function composition and binding– Allows fewer ad hoc function objects– Allows you to build functions as graphs (especially
chains and trees) of other functions
CSE 332: C++ STL functors
Composition and Binding with Function Objects• Function Composition
– f and g are both Adaptable Unary Functions– g return type is convertible to f argument type– (f ◦ g)(x) which is f(g(x)) can be written using unary_compose<f,g> or compose1(f,g)
• Function Binding– Adaptable Binary Function to Adaptable Unary Function– Bind first argument using binder1st<BinaryFun>
• Where f is an object of type binder1st<F>• f(x) F(c,x) where c is constant
– Bind second argument using binder2nd<BinaryFun>• Where f is an object of type binder2nd<F>• f(x) F(x,c) where c is constant
CSE 332: C++ STL functors
vector<double> angles; // ... push in some radian values ...vector<double> sines;const double pi = 3.14159265358979323846; transform(angles.begin(), angles.end(), sines.begin(),
compose1(negate<double>(), compose1(ptr_fun(sin),
bind2nd(multiplies<double>(),
pi / 180.0))));
• Calculate negative of sine of angles in degrees• Performed as a sequence of three operations
– Conversion of degrees to radians – Calculation of sine– Negation
Example of Function Composition
CSE 332: C++ STL functors
• Carry out operations in some specified order
template <class R, class List> class Chain {
Fun2& operator()(const Fun1<R, List>& fun1, const Fun2<R, List>& fun2)
{ fun1(); return fun2();
}};
Example of Explicit Call Chains
CSE 332: C++ STL functors
Member Function Adaptors
• Allows use of member functions as Function Objects• Similar adaptors available for non-member functions• Take an X* or X& argument and call one of the X
object’s member functions through that argument• If the member function is virtual, call is polymorphic• Three variations
– Argument type X* vs. X&– Member Function takes zero vs. one argument– Encapsulates non-const vs. const member function
CSE 332: C++ STL functors
Member Function Adaptor Example
struct B { virtual void print() = 0; };
struct D1 : public B { void print() { cout << "I'm a D1" << endl; } };
struct D2 : public B { void print() { cout << "I'm a D2" << endl; } };
int main(int, char **) { vector<B*> v; v.push_back(new D1); v.push_back(new D2);
v.push_back(new D2); v.push_back(new D1); for_each(v.begin(), v.end(), mem_fun(& B::print));return 0;
}
CSE 332: C++ STL functors
Concluding Remarks
• Passing parameters to Function Objects– Can do by value or by reference– Same kinds of aliasing issues, etc. as with any other object
• Watch performance with many small function objects– Watch out especially for creation, destruction overhead– May want to inline functors constructors, destructors– Put function objects on stack instead of heap
• Functors offer powerful, general mechanisms– Reduce programming complexity, increase reuse– Illustrate several new uses of generic programming– Could go farther with parameterization than just algorithms
• Use functors to make smarter iterators and containers