Generically, function objects are instances of a class with member functionoperator()
defined. This member function allows the object to be used with the same syntax as a regular function call, and therefore its type can be used as template parameter when a generic function type is expected.
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
template<class T>
class CSum {
private:
T sum;
public:
CSum() { sum = 0; }
void operator()(T n){
sum += n;
}
T GetSum() {
return sum;
}
};
int main(){
vector<int> v;
for (int i=0; i<=100; i++){
v.push_back(i);
}
CSum<int> o = for_each(v.begin(), v.end(), CSum<int>());
cout << o.GetSum() << endl;
return 0;
}
The function object sum all the numbers in a vector.
1. function object overload operator().
2. in the for_each, call the function object by its constructor.
3. CSum<int> o receives final result.
A good review is here and here.
We could also inherint from unary_function class
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
template <class inputPar, class outPar>
class CSum : public unary_function<inputPar, outPar> {
private:
outPar sum;
public:
CSum() { sum = 0; }
void operator()(inputPar n){
sum += n;
}
outPar getSum() { return sum; }
};
int main(){
double temp;
vector<int> v1;
for(int i=1; i<=100; i++){
v1.push_back(i);
}
vector<double> v2;
for(int i=1; i<=100; i++){
temp = i/100.0;
v2.push_back(temp);
}
CSum<int, int> s1 = for_each(v1.begin(), v1.end(), CSum<int, int>());
CSum<double, double> s2 = for_each(v2.begin(), v2.end(), CSum<double, double>());
cout << s1.getSum() << endl;
cout << s2.getSum() << endl;
return 0;
}
Let us look binary_function. We first define a student class, contains student name and grade, then sort the student vector.
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
class Student {
public:
string name;
int grade;
Student(string name, int grade){
this->name = name;
this->grade = grade;
}
bool operator<(const Student &s) const {
return grade < s.grade;
}
void printInfor(){
cout << name << "\t" << grade << endl;
}
};
template <class inPar1, class inPar2>
class binary_sort : public binary_function<inPar1, inPar2, bool>{
public:
bool operator()(inPar1 s1, inPar2 s2){
return s1 < s2;
}
};
int main(){
Student s1("Sam", 60);
Student s2("Tom", 49);
Student s3("Jim", 71);
Student s4("David", 30);
vector<Student> v;
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
v.push_back(s4);
sort(v.begin(), v.end(), binary_sort<const Student &, const Student &>());
vector<Student>::iterator itr = v.begin();
while (itr != v.end()){
itr->printInfor();
itr++;
}
return 0;
}
stl has some build-in function objects
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
int main (){
/* create an object, and use the functions */
plus<int> oplus;
minus<int> ominus;
multiplies<int> omultiple;
divides<int> odivides;
modulus<int> omodulus;
negate<int> onegate;
cout << oplus(2,4) << endl;
cout << ominus(4,2) << endl;
cout << omultiple(4,2) << endl;
cout << odivides(4,2) << endl;
cout << omodulus(4,2) << endl;
cout << onegate(4) << endl;
/* use a temporary object, call the operator */
cout << plus<int>()(2,4) << endl;
cout << minus<int>()(4,2) << endl;
cout << multiplies<int>()(4,2) << endl;
cout << divides<int>()(4,2) << endl;
cout << modulus<int>()(4,2) << endl;
cout << negate<int>()(4) << endl;
return 0;
}
For simple build-in data type, we could directly use these function objects. But for complex data structure, we need to overload such operators within class. STL has complex number, here just an illustration.
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
class Complex {
public:
double real;
double image;
Complex():real(0.0),image(0.0){}
Complex(double real_, double image_):real(real_),image(image_){}
Complex operator+(const Complex& c) const {
Complex v;
v.real = real + c.real;
v.image = image + c.image;
return v;
}
void print(){
cout << real << "+" << image << "i" << endl;
}
};
int main(){
Complex c1(3, 4.5);
Complex c2(3.5, 4);
Complex c3 = c1 + c2;
Complex c4 = plus<Complex>()(c1, c2);
c3.print();
c4.print();
cout << equal_to<Complex>()(c3, c4) << endl;
cout << equal_to<Complex>()(c1, c2) << endl;
Complex c;
vector<Complex> v;
v.push_back(c1);
v.push_back(c2);
v.push_back(c3);
v.push_back(c4);
Complex result = accumulate(v.begin(), v.end(), c, plus<Complex>());
result.print();
}
Besides simple unary_function and binary_function base classes, we also have function adapters.
1. bind2nd(function, value);
2. bind1nd(function, value);
3. not1(function);
4. not2(function);
bind2nd takes a binary_function as a parameter, and fix its second parameter to value.
bind1nd takes a binary_function as a parameter, and fix its first parameter to value.
not1 takes an unary_function as input, and logically reverse its result.
not2 takes a binary_function as input, and logically reverse its result.
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
for(int i=0; i<10; i++){
v.push_back(i+1);
}
vector<int>::iterator itr = v.begin();
while (itr!=v.end()){
cout << *itr << endl;
itr++;
}
int ncout = count_if(v.begin(), v.end(), bind2nd(less<int>(), 4));
cout << ncout << endl;
return 0;
}
This example first construct a vector, and see whether its element is less than 4, count the number.
bind2nd(less<int>(), 4)
use less<int>() function, it is a binary_function, however, we use adapter to fix it second parameter to 4, so we could use it as an unary_function.
Above is for the build-in function, could we use class member function? Sure, we usemem_fun_ref andmem_fun. mem_fun_ref is applied for objects, mem_fun is applied to pointers to objects.
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
class Student{
public:
string strNO;
string strName;
Student(string strNO_, string strName_):strNO(strNO_), strName(strName_){}
void printInfo(){
cout << strNO << ":" << strName << endl;
}
};
int main(){
Student s1("200001", "Tim");
Student s2("200002", "Tony");
Student s3("200003", "David");
vector<Student> v;
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
for_each(v.begin(), v.end(), mem_fun_ref(&Student::printInfo));
Student* ps1 = new Student("200001", "Tim");
Student* ps2 = new Student("200002", "Tony");
Student* ps3 = new Student("200003", "David");
vector<Student*> pv;
pv.push_back(ps1);
pv.push_back(ps2);
pv.push_back(ps3);
for_each(pv.begin(), pv.end(), mem_fun(&Student::printInfo));
return 0;
}
We can also use ordinary function via ptr_fun adapter.
#include <functional>
#include <vector>
using namespace std;
bool g(int x, int y){
return x > y;
}
int main(){
vector<int> v;
for(int i=0; i<10; i++){
v.push_back(i+1);
}
vector<int>::iterator itr = v.begin();
while(itr!=v.end()){
cout << *itr << endl;
itr++;
}
int ncout = count_if(v.begin(), v.end(), bind2nd(ptr_fun(g), 5));
cout << ncout << endl;
}
Some applications
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
class Shape{
public:
virtual void calArea() = 0;
};
class Circle : public Shape{
public:
Circle(double r_):r(r_){}
virtual void calArea(){
cout << 3.14*r*r << endl;
}
private:
double r;
};
class Rectangle : public Shape{
public:
Rectangle(double width_, double height_):width(width_), height(height_){}
virtual void calArea(){
cout << width*height << endl;
}
private:
double width, height;
};
int main(){
Circle* s1 = new Circle(0.5);
Rectangle* s2 = new Rectangle(2, 0.4);
vector<Shape*> v;
v.push_back(s1);
v.push_back(s2);
for_each(v.begin(), v.end(), mem_fun(&Shape::calArea));
return 0;
}
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
class Student{
public:
string strNO;
double Grade;
Student(string strNO_, double Grade_):strNO(strNO_), Grade(Grade_){}
};
template <class T>
class StudentIndex : public binary_function<T, T, bool>{
private:
vector<Student>&v;
public:
StudentIndex(vector<Student>&v_):v(v_){}
bool operator()(T a, T b){
return v.at(a).Grade < v.at(b).Grade;
}
};
int main(){
Student s1("1001", 70);
Student s2("1002", 60);
Student s3("1003", 80);
Student s4("1004", 74);
vector<Student> v;
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
v.push_back(s4);
vector<int>vIndex;
vIndex.push_back(0);
vIndex.push_back(1);
vIndex.push_back(2);
vIndex.push_back(3);
sort(vIndex.begin(), vIndex.end(), StudentIndex<int>(v));
vector<int>::iterator itr=vIndex.begin();
while(itr!=vIndex.end()){
cout << *itr << endl;
itr++;
}
return 0;
}