很多STL算法都使用函数对象——也叫函数符。函数符是可以以函数方式与()结合使用的对象。这包括函数名,指向函数的指针和重载了()运算符的类对象。
class Linear
{
double slope;
double y0;
public:
Linear(double sl_ = 2, double y_ = 0)
: slope(sl_), y0(y_) {}
double operator()(double x){return y0 + slope * x;}
}
重载的()运算符将使得能够像函数那样使用Linear对象。
Linear f1;
Linear f2(2.5, 10.0);
double y1 = f1(12.6);
double y2 = f2(0.9);
其中y1将使用表达式0 + 1 * 12.6来计算。
for_each(books.begin(), books.end(), ShowReview);
for_each()函数的第3个参数可以是常规函数,也可以是函数符。实际上,这里如何声明第3个参数呢,不能把它声明为函数指针,因为函数指针指定了参数类型。由于容器可以包含任意类型,所以预先无法知道应使用哪种参数类型。STL通过使用模板解决了这个问题。
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);
这样,标识符ShowReview的类型将为void(*)(const Review &),这也是赋给模板参数Function的类型。对于不同的函数调用,Function参数可以表示具有重载的()运算符的类类型。
函数符概念
• 生成器是不用参数就可以调用的函数符;
• 一元函数是用一个参数可以调用的函数符;
• 二元函数是用两个参数可以调用的函数符;
• 返回bool值的一元函数是谓词;
• 返回bool值的二元函数是二元谓词;
预定义的函数符
STL定义了对个基本函数符,它们执行如将两个值相加、比较两个值是否相等操作。提供这些函数对象是为了支持将函数作为参数的STL函数。
对于所有内置的算术运算符、关系运算符和逻辑运算符,STL提供了等价的函数符。
运算符 | 相应的函数 |
---|---|
+ | plus |
- | minus |
* | multiplies |
/ | divides |
% | modulus |
~ | negate |
== | equal_to |
!= | not_equal_to |
> | greater |
< | less |
>= | greater_equal |
<= | less_equal |
&& | logical_and |
|| | logical_or |
! | logical_not |
自适应函数符和函数适配器
上表列出的预定义函数符都是自适应的。实际上STL有5个相关的概念:自适应生成器、自适应一元函数、自适应二元函数、自适应谓词和自适应二元谓词。
使函数符成为自适应的原因是,它携带了标识参数类型和返回类型的typedef成员。这些成员分别是result_type、first_argument_type和second_argument_type。例如,plus对象的返回类型被标识为plus::result_type,这是int的typedef。
函数符自适应性的意义在于:函数适配器对象可以使用函数对象,并认为存在这些typedef成员。
C++11提供了函数指针和函数符的替代品——lambda表达式。