函数调用运算符必须是成员函数,函数调用运算符可以使类对象像函数一样被调用显示状态,如果类定义了调用运算符,则该类的对象称为函数对象

含有状态的函数对象类
定义一个打印string实参类型的类

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;
};

lambda是函数对象
编写lambda后,编译器会生成一个未命名类的未命名对象,同时在lambda类中含有一个重载的函数调用运算符。当在算法中使用lambda对象时,算***调用lambda对象,触发函数调用运算符,从而执行函数体内容进行比较

表示lambda及相应捕获行为的类
lambda表达式引用捕获的变量将由程序来保证存在,所以编译器不需要在类中存储这些量。
而通过值捕获的变量,将会拷贝到lambda中,这种情况下lambda类中将会有这些数据成员以及用于初始化该成员的构造函数,且lambda的构造、赋值、析构都不含默认函数,需要给出形参。

标准库定义的函数对象
可以使用标准库给出的函数模板构造函数对象,定义在functional中

plus<int> intAddd;//可以执行int加法的函数对象
int sum = intAdd(10, 20);

可调用对象
C++中的可调用对象包括函数、函数指针、lambda表达式、bind创建的对象、重载函数调用运算符的类
不同类型的调用对象可能具有相同的调用形式,即形参和返回类型相同,可以使用函数表来存储这些可调用对象的“指针”,从而集成使用。在C++中,使用map来进行实现比较容易

map<string, int(*)(int, int)>binops;
binops.insert({"+", add});//将add存入map

使用上面的方法,无法将lambda表达式存入,因为lambda表达式有自己的类类型,可以使用下面要讲的function标准库类型解决

标准库function类型
function定义在functional头文件中,是一个模板,需要提供该function类型能表示的对象的调用形式

function<int(int, int)> f1 = add;
function<int(int, int)> f2 = divide();
function<int(int, int)> f3 = [](int i,int j){return i*j};//构造三种function类型对象

使用function替代前面的类型,就可以全部插入map了

重载的函数与function
当有重载函数时,应该使用定义个函数指针或者构建lambda对象进行区分