函数对象
如果一个类定义了调用运算符,则该类的对象称作函数对象
(function object)。
含有状态的函数对象类
和其他类一样,函数对象类除了operator()之外,也可以包含其他成员。如:
#include <iostream>
#include "vector"
#include "string"
using namespace std;
class PrintString {
public:
PrintString(ostream &o = cout, char c = ' '): os(o), sep(c){ }
void operator() (const string &s) const { os << s << sep;}
private:
ostream &os;
char sep;
};
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
PrintString printer;
printer("test1:");
cout << endl;
vector<string> dd = {"ss", "ddd", "eeee"};
for_each(dd.begin(), dd.end(), PrintString(cerr, ' '));
ostream &os = cout;
char sep = '\n';
printer("test2:");
cout << endl;
for_each(dd.begin(), dd.end(), [&os, sep](const string &a){
os << a << sep;
});
return 0;
}
lambda是函数对象
[](const string &a, const string &b) {
return a.size() < b.size();
}
如上例中编写的lambda表达式,编译器会将该表达式翻译成一个为命名类的的未命名对象,如:
class ShorterString {
public:
bool operator() (const string &a, const string &b) const {
return a.size() < b.size();
}
};
表示lambda及相应捕获行为的类
当一个lambda表达式通过引用捕获变量时,将由程序负责确保lambda执行时引用所引的对象确实存在。因此,编译器可以直接使用该引用而无须在lambda产生的类中将其存储为数据成员。
size_t sz = 9;
auto wc = find_if(dd.begin(), dd.end(), [&sz](const string &a){
return a.size() >= sz;
});
相反,通过值捕获的变量被拷贝到lambda中。因此,这种lambda产生的类必须为每个值捕获的变量建立对应的数据成员,同时创建构造函数,令其使用捕获的变量的值来初始化数据成员。
lambda表达式:
size_t sz = 9;
auto wc = find_if(dd.begin(), dd.end(), [&sz](const string &a){
return a.size() >= sz;
});
产生的类如下:
class SizeComp {
public:
SizeComp(size_t n): sz(n){}
bool operator()(const string &s) const {
return s.size() >= sz;
}
private:
size_t sz;
};
标准库定义的函数对象
标准库定义了一组表示算术运算符、关系运算符和逻辑运算符的类,每个类分别定义了一个执行命名操作的调用运算符。
plus<int> intAdd;
int sum intAdd(1, 5); //等价于sum = 6
降序排序svec
sort(svec.begin(), svec.end(), greater<string>());
标准库定义的其他函数对象,详见:functional头文件
可调用对象与function
C++语言中有几种可调用的对象:函数、函数指针、lambda表达式、bind创建的对象以及重载了函数调用运算符的类。
和其他对象一样,可调用的对象也有类型。例如,每个lambda有它自己唯一的(未命名)类类型;函数及函数指针的类型则由其返回值类型和实参类型决定,等等。
然而,两个不同类型的可调用对象却可能共享同一种调用形式(call signature
)。调用形式指明了调用返回的类型以及传递给调用的实参类型。一种调用形式对应一个函数类型,例如:int(int, int)是一个函数类型,它接受两个int、返回一个int。
不同类型可能具有相同的调用形式
对于几个可调用对象共享同一种调用形式的情况,有时我们会希望把他们看成具有相同的类型。如:
int add(int i, int j) {return i +j;}
auto mod = [](int i, int j) {return i % j;};
struct divide {
int operator()(int denominator, int divisor) {
return denominator / divisor;
}
};
上面这些可调用对象分别对其参数执行了不同的算术运算,尽管它们的类型各不相同,但是共享同一种调用形式:int(int, int)
标准库function类型
我们可能希望使用这些可调用对象构建一个简单的桌面计算器。为了实现这一目的,可以定义一个function对象表。
map<string, function<int(int, int)>> binops = {
{"+", add},
{"-", std::minus<int>()},
{"/", divide()},
{"*", [](int i, int j) {return i * j;}},
{"%", mod}
};
调用方式如下:
binops["+"](10, 5);
binops["-"](10, 5);
binops["/"](10, 5);
binops["*"](10, 5);
binops["%"](10, 5);
网友评论