如果类定义了调用运算符(即圆括号),则该类的对象称作函数对象(function object)。因为可以调用这种对象,所以我们说这些对象的"行为像函数一样"。
函数对象常常作为泛型算法的实参,并代替函数指针使用。以sort()为例,sort(begin,end)接受两个迭代器作为其参数,默认利用元素类型的<运算符来实现排序。sort(begin,end,comp)则以用户定义的comp函数作为元素比较的根据。通常情况下,可以设计自己的比较函数comp,然后以函数指针当做算法的一个参数。但是函数指针不能满足STL对抽象性的要求,同时函数指针无法和STL其他组件搭配,产生更灵活的变化,因此需要使用函数对象。
STL的函数对象,根据操作数的个数划分,可分为一元和二元函数对象。根据功能划分,可分为算术运算、关系运算、逻辑运算三大类,每个类分别定义了一个执行命名操作的调用运算符。
STL的函数对象可以使算法更灵活,而更加灵活的关键,在于STL的函数对象的可适配性(adaptability)。STL的函数对象应该有能力被函数适配器修饰,彼此像积木一样地串接。为了拥有适配能力,每一个函数对象必须定义自己的相应类型,就像迭代器如果要融入STL,也必须依照规定定义自己的5个相应类型一样,这些相应类型是为了让适配器能够取出,获得函数对象的某些信息。
函数对象的相应类型主要用来表现函数参数类型和返回值类型。标准库在
template <typename _Arg, typename _Result>
struct unary_function
{
/// @c argument_type is the type of the argument
typedef _Arg argument_type;
/// @c result_type is the return type
typedef _Result result_type;
};
template <typename _Arg1, typename _Arg2, typename _Result>
struct binary_function
{
/// @c first_argument_type is the type of the first argument
typedef _Arg1 first_argument_type;
/// @c second_argument_type is the type of the second argument
typedef _Arg2 second_argument_type;
/// @c result_type is the return type
typedef _Result result_type;
};
算术类函数对象包括:plus
template <typename _Tp>
struct plus : public binary_function<_Tp, _Tp, _Tp>
{
_GLIBCXX14_CONSTEXPR
_Tp operator()(const _Tp &__x, const _Tp &__y) const
{
return __x + __y;
}
};
template <typename _Tp>
struct minus : public binary_function<_Tp, _Tp, _Tp>
{
_GLIBCXX14_CONSTEXPR
_Tp operator()(const _Tp &__x, const _Tp &__y) const
{
return __x - __y;
}
};
template <typename _Tp>
struct multiplies : public binary_function<_Tp, _Tp, _Tp>
{
_GLIBCXX14_CONSTEXPR
_Tp operator()(const _Tp &__x, const _Tp &__y) const
{
return __x * __y;
}
};
template <typename _Tp>
struct divides : public binary_function<_Tp, _Tp, _Tp>
{
_GLIBCXX14_CONSTEXPR
_Tp operator()(const _Tp &__x, const _Tp &__y) const
{
return __x / __y;
}
};
template <typename _Tp>
struct modulus : public binary_function<_Tp, _Tp, _Tp>
{
_GLIBCXX14_CONSTEXPR
_Tp operator()(const _Tp &__x, const _Tp &__y) const
{
return __x % __y;
}
};
template <typename _Tp>
struct negate : public unary_function<_Tp, _Tp>
{
_GLIBCXX14_CONSTEXPR
_Tp operator()(const _Tp &__x) const
{
return -__x;
}
};
#include
#include
using namespace std;
int main()
{
plus<int> intplus;
minus<int> intminus;
multiplies<int> intmultiplies;
divides<int> intdivides;
modulus<int> intmodulus;
negate<int> intnegate;
cout<<intplus(1,2)<<endl; //3
cout<<intminus(1,2)<<endl; //-1
cout<<intmultiplies(1,2)<<endl; //2
cout<<intdivides(1,2)<<endl; //0
cout<<intmodulus(1,2)<<endl; //1
cout<<intnegate(1)<<endl; //-1
return 0;
}
关系类函数对象包括:equal_to
template <typename _Tp>
struct equal_to : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x == __y;
}
};
template <typename _Tp>
struct not_equal_to : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x != __y;
}
};
template <typename _Tp>
struct greater : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x > __y;
}
};
template <typename _Tp>
struct less : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x < __y;
}
};
template <typename _Tp>
struct greater_equal : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x >= __y;
}
};
template <typename _Tp>
struct less_equal : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x <= __y;
}
};
#include
#include
using namespace std;
int main()
{
equal_to<int> intequal_to;
not_equal_to<int> intnotequal_to;
greater<int> intgreater;
greater_equal<int> intgreater_equal;
less<int> intless;
less_equal<int> intless_equal;
cout<<intequal_to(1,2)<<endl; //0
cout<<intnotequal_to(1,2)<<endl; //1
cout<<intgreater(1,2)<<endl; //0
cout<<intgreater_equal(1,2)<<endl; //0
cout<<intless(1,2)<<endl; //1
cout<<intless_equal(1,2)<<endl; //1
return 0;
}
逻辑函数对象包括:logical_and
template <typename _Tp>
struct logical_and : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x && __y;
}
};
template <typename _Tp>
struct logical_or : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x, const _Tp &__y) const
{
return __x || __y;
}
};
template <typename _Tp>
struct logical_not : public unary_function<_Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp &__x) const
{
return !__x;
}
};
#include
#include
using namespace std;
int main()
{
logical_and<int> int_and;
logical_or<int> int_or;
logical_not<int> int_not;
cout<<int_and(1,0)<<endl; //0
cout<<int_or(1,0)<<endl; //1
cout<<int_not(1)<<endl; //0
return 0;
}
template <typename _Tp>
struct _Identity
: public unary_function<_Tp, _Tp>
{
_Tp &
operator()(_Tp &__x) const
{
return __x;
}
const _Tp &
operator()(const _Tp &__x) const
{
return __x;
}
};
// Partial specialization, avoids confusing errors in e.g. std::set.
template <typename _Tp>
struct _Identity<const _Tp> : _Identity<_Tp>
{
};
template <typename _Pair>
struct _Select1st
: public unary_function<_Pair, typename _Pair::first_type>
{
typename _Pair::first_type &
operator()(_Pair &__x) const
{
return __x.first;
}
const typename _Pair::first_type &
operator()(const _Pair &__x) const
{
return __x.first;
}
#if __cplusplus >= 201103L
template <typename _Pair2>
typename _Pair2::first_type &
operator()(_Pair2 &__x) const
{
return __x.first;
}
template <typename _Pair2>
const typename _Pair2::first_type &
operator()(const _Pair2 &__x) const
{
return __x.first;
}
#endif
};
template <typename _Pair>
struct _Select2nd
: public unary_function<_Pair, typename _Pair::second_type>
{
typename _Pair::second_type &
operator()(_Pair &__x) const
{
return __x.second;
}
const typename _Pair::second_type &
operator()(const _Pair &__x) const
{
return __x.second;
}
};