C++函数对象
定义:函数对象(Function Object)指的是定义了operator()的对象
一般形式:
class FunctionObjectType{
public:
void operator() (){
//statements...
}
};
优点:
- 比一般函数更灵巧,可以拥有状态
- 每个函数对象都有类型,可以将函数对象的类型当做template参数传递,容器类型也会因为函数对象类型的不同而不同
- 执行速度比函数指针稍快
用法一:以函数对象作为排序准则
std::set要求排序方法有“类型”,所以不能使用普通函数,但是可以使用函数对象。
#include <algorithm>
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;
class Person
{
public:
Person(string lastname, string firstname)
: _firstname(firstname)
, _lastname(lastname)
{
}
string firstname() const
{
return _firstname;
}
string lastname() const
{
return _lastname;
}
private:
string _firstname = nullptr;
string _lastname = nullptr;
};
class PersonSortCriterion
{
public:
bool operator()(const Person& p1, const Person& p2) const
{
return p1.lastname() < p2.lastname() ||
(p1.lastname() == p2.lastname() && p1.firstname() < p2.firstname());
}
};
int main(void)
{
set<Person, PersonSortCriterion> coll;
Person p1("yu", "g");
Person p2("an", "yu");
Person p3("xiao", "ming");
Person p4("xi", "biaoge");
Person p5("u", "ong");
coll.insert(p1);
coll.insert(p2);
coll.insert(p3);
coll.insert(p4);
coll.insert(p5);
for (auto i : coll) {
cout << i.lastname() << ", " << i.firstname() << endl;
}
return 0;
}
用法二:使用函数对象的内部状态
只要改变operator()就可以产生复杂的序列。
默认情况下,函数对象进行值传递,一次算法不会改变函数对象的状态。
如:
IntSequence seq(1);
std::generate_n(back_inserter(coll), 9, seq);
这种方式会使得从一开始产生序列。
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
class IntSequence
{
private:
int value;
public:
IntSequence (int initialValue) : value(initialValue) {}
int operator()()
{
return value++;
}
int getValue()
{
return value;
}
};
int main(void)
{
std::list<int> coll;
//插入数值:1~9
std::generate_n(back_inserter(coll), 9, IntSequence(1));
for (auto i : coll) {
std::cout << i << " ";
}
std::cout << std::endl;
//替换第二个数到最后一个数
std::generate(std::next(coll.begin()),std::prev(coll.end()),IntSequence(42));
for (auto i : coll) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
从运用了函数对象的算法中获取结果
方法有三种:
- 在外部持有状态,并让函数对象指向它
- 以引用方式传递函数对象
- 利用for_each()算法的返回值
第一种方法:
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
class IntSequence
{
private:
int& value;
public:
IntSequence (int& initialValue) : value(initialValue) {}
int operator()()
{
return value++;
}
int getValue()
{
return value;
}
};
int main(void)
{
int a = 1;
IntSequence seq(a);
std::list<int> coll;
//插入数值:1~9
std::generate_n<std::back_insert_iterator<std::list<int>>, int, IntSequence&>(std::back_inserter(coll), 9, seq);
for (auto i : coll) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "a = " << a << std::endl;
//再次插入10~13
std::generate_n(std::back_inserter(coll), 4, seq);
for (auto i : coll) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "a = " << a << std::endl;
return 0;
}
第二种方法:
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
class IntSequence
{
private:
int value;
public:
IntSequence (int initialValue) : value(initialValue) {}
int operator()()
{
return value++;
}
int getValue()
{
return value;
}
};
int main(void)
{
IntSequence seq(1);
std::list<int> coll;
//插入数值:1~9
std::generate_n<std::back_insert_iterator<std::list<int>>, int, IntSequence&>(std::back_inserter(coll), 9, seq);
for (auto i : coll) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << seq.getValue() << std::endl;
//再次插入42~45
std::generate_n(std::back_inserter(coll), 4, IntSequence(42));
for (auto i : coll) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << seq.getValue() << std::endl;
return 0;
}
第三种方法:for_each()算法可以回传函数对象的状态
在这个程序中for_each()会返回函数对象,也就是以一个MeanValue对象
#include <iostream>
#include <vector>
#include <algorithm>
class MeanValue
{
private:
long num;
long sum;
public:
MeanValue() : num(0), sum(0) {}
void operator()(int elem)
{
++num;
sum += elem;
}
double meanvalue()
{
return static_cast<double>(sum) / static_cast<double>(num);
}
};
int main(void)
{
std::vector<int> coll = {2,4,56,453,35,7789,9,454,111,24,9012};
MeanValue mv = std::for_each(coll.begin(),coll.end(),MeanValue());
std::cout << "mean value = " << mv.meanvalue() << std::endl;
return 0;
}