在C++中,使用仿函数和普通函数进行谓词操作各有其优缺点。我们来分别分析这两种写法的好处:
比如说我想要统计大于20的元素个数
仿函数(Functor)
class Greater20 {
public:
bool operator()(int val) {
return val > 20;
}
};
好处:
-
状态保存:仿函数可以保存状态,可以在类中包含成员变量,并在调用时使用这些成员变量。这使得仿函数在需要携带上下文信息时特别有用。
-
可组合性和复用性:仿函数可以被定义为模板类,这样可以更容易地复用和组合。例如,可以创建一个通用的比较类,然后在不同情况下实例化。
-
类型安全:由于仿函数是类的一部分,可以利用C++的类型系统进行更多的类型检查,减少运行时错误的可能性。
例子:
class Greater {
public:
Greater(int threshold) : threshold_(threshold) {}
bool operator()(int val) const {
return val > threshold_;
}
private:
int threshold_;
};
void test02() {
vector<int> v = {10, 20, 40, 30, 50};
int threshold = 25;
int num = count_if(v.begin(), v.end(), Greater(threshold));
cout << "Count greater than " << threshold << ": " << num << endl;
}
普通函数
bool greater20(int val) {
return val > 20;
}
好处:
-
简单和直接:普通函数定义和使用都非常简单,对于不需要状态和上下文信息的简单操作,函数更加直观和易读。
-
性能:普通函数没有额外的类实例化开销,可能在某些情况下性能稍好。
-
灵活性:普通函数可以轻松使用C++11及以上版本的lambda表达式,可以在需要时定义内联的、一次性的函数对象。
例子:
void test03() {
vector<int> v = {10, 20, 40, 30, 50};
int num = count_if(v.begin(), v.end(), [](int val) { return val > 25; });
cout << "Count greater than 25: " << num << endl;
}
总结
仿函数适用于需要携带状态或者需要更多类型安全和可组合性的情况。它们在需要定义复杂的条件或多次复用时非常有用。
普通函数则适用于简单、一次性、无状态的操作,尤其在结合lambda表达式使用时更加简洁和灵活。
具体使用哪种方式,取决于你的需求:
- 如果你需要一个简单的、一次性的检查,使用普通函数或lambda表达式。
- 如果你需要携带状态,或者需要一个可以复用的、复杂的检查逻辑,使用仿函数。
完整示例代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
class Greater20 {
public:
bool operator()(int val) const {
return val > 20;
}
};
bool greater20(int val) {
return val > 20;
}
void test01() {
vector<int> v = {10, 20, 40, 30, 50};
int num1 = count_if(v.begin(), v.end(), Greater20());
int num2 = count_if(v.begin(), v.end(), greater20);
cout << num1 << " " << num2 << endl;
}
int main() {
test01();
return 0;
}
上述代码中,Greater20
是仿函数,而 greater20
是普通函数,test01
展示了如何使用这两种方法进行计数操作。