函数调用运算符为 (),放在函数名后边提供实参列表,实现函数调用。如果 C++ 的 class、struct 重载了函数调用运算符,那么可以像使用函数一样使用它们的对象,即可以 “调用” 这些对象。调用对象实际是在执行重载函数调用运算符(函数)

        如果类定义了函数调用运算符,则该类的对象称为函数对象可调用对象。这些函数对象常用于泛型算法、哈希函数。

一、函数调用运算符重载语法

返回值类型 operator()(param list) 函数修饰符 {函数体}

// 1. 摘自 <<C++ primer>>
struct absInt {
    int operator()(int val) const {
        return val < 0 ? -val : val;
    }
};

// 2. 摘自 /usr/include/c++/9/bits/functional_hash.h
// Primary class template hash.
  template<typename _Tp>
    struct hash;

/// Specialization for float.
template<>
struct hash<float> : public __hash_base<size_t, float> 
{
    size_t
    operator()(float __val) const noexcept {
	    // 0 and -0 both hash to zero.
	    return __val != 0.0f ? std::_Hash_impl::hash(__val) : 0;
    }
};

与其他类一样,函数对象类也可以包含其他成员,生成包含状态的函数对象类

// 摘自 <<C++ primer>> 
class PrintString
{
public:
   PrintString(ostream &o = cout, char c = ' ') : os(o), sep(c) {}
   void operator()(const string &s) {
        os << s << sep;
   }

private:
    ostream &os;
    char sep;
};

函数对象常常用于泛型算法的实参来提高性能,比如 for_each 算法:

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

class PrintString
{
public:
   PrintString(std::ostream &o = std::cout, char c = ' ') : os(o), sep(c) {}
   void operator()(const std::string &s) {
        os << s << sep;
   }

private:
    std::ostream &os;
    char sep;
};

int main(int argc, char *argv[]) {
    std::vector<std::string> vs = {"123", "456", "789", "abc"};

    // 第三个参数是一个函数对象类(PrintString)的临时对象
    std::for_each(vs.begin(), vs.end(), PrintString(std::cout, '\n'));

}

// for_each 可能的实现
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
    for (; first != last; ++first) {
        f(*first);
    }
    return f; // C++11 起隐式移动
}

二、总结 

除了重载函数调用运算符类的对象 ,还有 lambda都属于可调用对象,使用它们可带来便捷性和高效性。

更多推荐