试想有一排序函数sort(int arr[])默认为升序排序,如果想更改为降序排列,最直接的方法就是在函数体中修改比较运算符,但这种修改函数体的方法不够灵活,特别是如果sort(int arr[])要封装到库(接口与实现分离)时,库使用者是无法去修改函数体的。理想的方法是修改接口,在接口在添加一函数指针做为形式参数,在函数体中调用函数指针,这样,函数体中的代码就可以固定下来,而选择升序还是降序排列,则由函数指针指向的函数来决定。
函数指针、函数对象、Lambda表达式都可以实现同样的功能:
#include
#include
using namespace std;
struct FuncObj {
constexpr FuncObj() = default;
int operator()(int a) {
return run(a);
}
// this is a non-capturing lambda, the operator can be
// in a static function
static int run(int a) {
return a;
}
};
typedef int (*funcp)(int a);
//template
//int func(int a)
int func(int a, funcp foo)
{
foo(a);
}
int func(int a,FuncObj lt)
{
lt(a);
}
int funcpRelated(int a)
{
return a;
}
int main()
{
auto lambda = [](int a) { return a; };
funcp ptr = lambda; // 类型相同,不能捕捉
cout< f_int_obj = FuncObj();
cout<(1); // ---> this is working
return 0;
}
函数指针、函数对象、Lambda表达式对STL算法的使用:
#include
#include
#include
#include
#include
const long Size1 = 39L;
const long Size2 = 100*Size1;
const long Size3 = 100*Size2;
bool f3(int x) {return x % 3 == 0;}
bool f13(int x) {return x % 13 == 0;}
int main()
{
using std::cout;
std::vector numbers(Size1);
std::srand(std::time(0));
std::generate(numbers.begin(), numbers.end(), std::rand);
// using function pointers
cout << "Sample size = " << Size1 << '
';
int count3 = std::count_if(numbers.begin(), numbers.end(), f3);
cout << "Count of numbers pisible by 3: " << count3 << '
';
int count13 = std::count_if(numbers.begin(), numbers.end(), f13);
cout << "Count of numbers pisible by 13: " << count13 << "
";
// increase number of numbers
numbers.resize(Size2);
std::generate(numbers.begin(), numbers.end(), std::rand);
cout << "Sample size = " << Size2 << '
';
// using a functor
class f_mod
{
private:
int dv;
public:
f_mod(int d = 1) : dv(d) {}
bool operator()(int x) {return x % dv == 0;}
};
count3 = std::count_if(numbers.begin(), numbers.end(), f_mod(3));
cout << "Count of numbers pisible by 3: " << count3 << '
';
count13 = std::count_if(numbers.begin(), numbers.end(), f_mod(13));
cout << "Count of numbers pisible by 13: " << count13 << "
";
// increase number of numbers again
numbers.resize(Size3);
std::generate(numbers.begin(), numbers.end(), std::rand);
cout << "Sample size = " << Size3 << '
';
// using lambdas
count3 = std::count_if(numbers.begin(), numbers.end(),
[](int x){return x % 3 == 0;});
cout << "Count of numbers pisible by 3: " << count3 << '
';
count13 = std::count_if(numbers.begin(), numbers.end(),
[](int x){return x % 13 == 0;});
cout << "Count of numbers pisible by 13: " << count13 << '
';
// std::cin.get();
return 0;
}
输出:
Sample size = 39
Count of numbers pisible by 3: 14
Count of numbers pisible by 13: 0
Sample size = 3900
Count of numbers pisible by 3: 1365
Count of numbers pisible by 13: 289
Sample size = 390000
Count of numbers pisible by 3: 129968
Count of numbers pisible by 13: 30393
函数数指针、函数对象、Lambda表达式的使用,可以从以下几个方面来区别:
1 距离:让定义位于使用的地方最近是一种最佳的选择。这是Lambda表达式的优势。函数对象是次优的选择,因为函数对象的类也可以定义在函数内部。最差的是函数指针了,距离最远。
2 简洁:是指代码的简洁度。Lambda表达式的代码最简洁,函数指针次之,函数对象虽然相对于函数指针来说,可以实现状态数据的存储,但代码的简洁度最差。
3 效率
这三种方法的相对效率取决于编译器内联那些东西。函数指针方法阻止了内联(能够内联的代码,执行效率比较高),因为编译器传统上不会内联其地址被获取的函数,因为函数地址的概念意味着非内联函数。而函数对象和lambda通常不会阻止内联。
4 功能
lambda有一些额外的功能。具体地说,lambad可访问作用域内的任何动态变量;要捕获要使用 的变量,可将其名称放在中括号内。如果只指定了变量名,如[z],将按值访问变量;如果在名称前加上& , 如[&count],将按引用访问变量。[&]让您能够按引用访问所有动态变量,而[=]让您能够按值访问所有动态变 量。还可混合使用这两种方式,例如[ted, &ed]让您能够按值访问ted以及按引用访问ed ,[&, ted]让您能够按值访问ted以及按引用访问其他所有动态变量,[=,&ed]让您能够按引用访问ed以及按值访问其他所有动态变量。
看下面的实例:
// lambda1.cpp -- use captured variables
#include
#include
#include
#include
#include
const long Size = 390000L;
int main()
{
using std::cout;
std::vector numbers(Size);
std::srand(std::time(0));
std::generate(numbers.begin(), numbers.end(), std::rand);
cout << "Sample size = " << Size << '
';
// using lambdas
int count3 = std::count_if(numbers.begin(), numbers.end(),
[](int x){return x % 3 == 0;});
cout << "Count of numbers pisible by 3: " << count3 << '
';
int count13 = 0;
std::for_each(numbers.begin(), numbers.end(),
[&count13](int x){count13 += x % 13 == 0;});
cout << "Count of numbers pisible by 13: " << count13 << '
';
// using a single lambda
count3 = count13 = 0;
std::for_each(numbers.begin(), numbers.end(),
[&](int x){count3 += x % 3 == 0; count13 += x % 13 == 0;});
cout << "Count of numbers pisible by 3: " << count3 << '
';
cout << "Count of numbers pisible by 13: " << count13 << '
';
// std::cin.get();
return 0;
}
输出:
Sample size = 390000
Count of numbers pisible by 3: 130144
Count of numbers pisible by 13: 29939
Count of numbers pisible by 3: 130144
Count of numbers pisible by 13: 29939
用表格综合一下以上4项区别:
表格数据:
函数指针 | 函数对象 | lambda表达式 | ||
距离 | 定位位置与使用位置 | 最差 | 次优 | 最优 |
简洁 | 代码的简洁度 | 次优 | 最差 | 最优 |
效率 | 可内联的代码效率要高 | 不能内联 | 可内联 | 可内联 |
功能 | 额外功能 | 可访问作用域内的任何动态变量 |
ref
StephenPrata:《C++ Primer Plus(6th 2011)》
-End-
页面更新:2024-03-05
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号