C++仿函数和typename的用法

1.仿函数的定义是很简单的,就是一个重载了括号()运算符的类,也被称为函数对象。

主要是用于个性化扩展算法对象。stl中实现了好多算法,每个算法都可以完成日常的大部分工作,设计者还允许你在这些强大的算法上再插上别的功能。

怎么插?插的比较泛型和object oriented?这就需要直接把你想添加的功能做参数传给算法对象,于是他们就弄出来个函数对象,让你用起来像函数,但插起来像普通的C++类

比如定义一个仿函数

template <class T>

class functor

{

T operator()(T x){return x+x;}

};

cout<<functor<int>()(2);

好了这就是仿函数。

2.typename

先看问题

template <class T>

class Test

{

typedef T argument_type;

}

 

template <class T2>

class Test2

{

T2::argument_type*x;

}

Test2<Test> obj;

cout<<obj.x;

Test2模板类有点特别,它实例化的时候模板参数必须要有argument_type这个成员,而且这个arguement_type也比较特别,它是一个类型定义成员,不是用来运算而是用来定义别的变量。按惯例编译器会把T2::argument_type这种写法当作静态成员处理,但是这里如果按照静态成员去解析一个类型定义显然会报错,而且即使编译器考虑到T2::argument_type有可能是个类型定义,那它也无从追溯,对于模板参数T2及其成员,在Test2实例化之前编译器根本不知道这些信息,除非加typename显式声明。

另外,让我们再从编译器的角度看待实例化。

我们认为定义对象是一个实例化的过程,其实编译器得到这样一个指示后并不为对象分配内存,它仍然是为程序的运转做规划,编译后的文件实际上就是一份程序执行方案。何为实例化,答案是we don't care。我们当然是只关注问题的解决,而不是概念本身。

 

转载于:https://www.cnblogs.com/sky-view/p/3246652.html

<think>我们正在讨论C++中的仿函数(Functor)。根据引用内容,仿函数是重载了operator()的类或结构体的对象,可以像函数一样被调用。它们有广泛的应用场景,如STL算法、回调机制、函数适配器等。根据引用[1]:仿函数在STL算法、回调机制、函数适配器等场景中有着广泛的应用。引用[2]提到:仿函数可以重载函数调用运算符operator(),使得该类对象可以像函数一样被调用并返回一个值。仿函数可以接受任意数量类型的参数,并且可以使用模板来实现通用性。其特点是灵活性高、可用于STL算法等。引用[3]给出了一个仿函数的例子:一个比较大小的仿函数,可以在STL算法中用作比较准则。引用[4]展示了使用标准库中的仿函数std::plus<int>进行加法操作,并将其存储在std::function对象中。引用[5]则展示了在for_each算法中使用仿函数(通过bind绑定)的例子。因此,我们可以总结出仿函数的主要用途应用场景如下:1.STL算法:许多STL算法(如sort,for_each,transform等)允许传递一个函数对象(仿函数)作为谓词(predicate)或操作函数。例如,在排序时,我们可以传递一个比较仿函数来定义排序规则。2.回调机制:仿函数可以作为回调函数使用,因为它们可以像函数指针一样被传递,但比函数指针更灵活(可以携带状态)。3.函数适配器:仿函数可以与其他函数适配器(如std::bind,std::function)结合使用,实现函数的组合适配。4.策略模式:仿函数可以用于实现策略模式,将算法策略封装在仿函数中,使得算法策略可以灵活替换。5.状态保持:与普通函数不同,仿函数可以拥有状态(因为它们是对象),可以在多次调用之间保持状态。下面我们将详细介绍仿函数的使用场景,并给出代码示例。一、在STL算法中的应用例如,使用自定义的仿函数作为排序准则:```cpp#include<iostream>#include<vector>#include<algorithm>//自定义一个比较仿函数:按降序排列classCompareDesc{public:booloperator()(inta,intb)const{returna>b;}};intmain(){std::vector<int>vec={5,2,8,3,1};//使用仿函数对象进行降序排序std::sort(vec.begin(),vec.end(),CompareDesc());for(intnum:vec){std::cout<<num<<"";}return0;}```输出:85321二、在回调机制中的应用仿函数可以作为回调传递给某个函数,例如在事件处理系统中:```cpp#include<iostream>//事件处理器类classEventHandler{public:voidhandleEvent(conststd::string&eventName){std::cout<<"Handlingevent:"<<eventName<<std::endl;}};//仿函数封装事件处理classEventFunctor{EventHandler&handler;public:EventFunctor(EventHandler&h):handler(h){}voidoperator()(conststd::string&eventName){handler.handleEvent(eventName);}};intmain(){EventHandlerhandler;EventFunctoreventCallback(handler);//模拟事件触发,调用仿函数eventCallback("ButtonClick");return0;}```三、与函数适配器结合使用std::bindstd::function与仿函数结合,实现更灵活的函数组合:```cpp#include<iostream>#include<functional>classMultiplier{public:intoperator()(inta,intb)const{returna*b;}};intmain(){Multipliermult;//使用std::bind将仿函数绑定,固定一个参数automultiplyByTwo=std::bind(mult,std::placeholders::_1,2);std::cout<<multiplyByTwo(5)<<std::endl;//输出10return0;}```四、实现策略模式仿函数可以作为策略对象传递给某个算法类,使得算法可以在运行时改变策略。```cpp#include<iostream>//策略接口:计算策略classCalculateStrategy{public:virtualintexecute(inta,intb)const=0;};//加法策略classAddStrategy:publicCalculateStrategy{public:intexecute(inta,intb)constoverride{returna+b;}};//减法策略classSubtractStrategy:publicCalculateStrategy{public:intexecute(inta,intb)constoverride{returna-b;}};//计算器类,使用策略classCalculator{constCalculateStrategy&strategy;public:Calculator(constCalculateStrategy&s):strategy(s){}intcompute(inta,intb){returnstrategy.execute(a,b);}};intmain(){AddStrategyadd;SubtractStrategysub;Calculatorcalc1(add);Calculatorcalc2(sub);std::cout<<calc1.compute(10,5)<<std::endl;//15std::cout<<calc2.compute(10,5)<<std::endl;//5return0;}```五、保持状态仿函数可以携带状态,例如计数调用了多少次:```cpp#include<iostream>#include<vector>#include<algorithm>classCountIfFunctor{intcount;public:CountIfFunctor():count(0){}booloperator()(intnum){if(num%2==0){count++;returntrue;}returnfalse;}intgetCount()const{returncount;}};intmain(){std::vector<int>vec={1,2,3,4,5,6};CountIfFunctorcounter;//注意:std::for_each会返回传入的函数对象,所以我们可以获取其状态counter=std::for_each(vec.begin(),vec.end(),counter);std::cout<<"Numberofevennumbers:"<<counter.getCount()<<std::endl;return0;}```总结:仿函数C++中是一个强大的工具,它提供了比函数指针更多的灵活性,特别是能够携带状态利用面向对象的特性。它在STL算法、回调、策略模式等场景中发挥着重要作用。§§相关问题§§1.仿函数函数指针有什么区别?2.在C++11及以后,lambda表达式仿函数之间有什么关系?3.如何实现一个泛型的仿函数(模板仿函数)?4.仿函数在性能上有什么优势?</think>### C++ 仿函数详解:使用场景与功能介绍 #### 一、仿函数基本概念 仿函数(Functor)是重载了函数调用运算符 `operator()` 的类或结构体对象,使其能像普通函数一样被调用[^1][^2]。核心特点: 1. **对象行为函数化**:通过 `operator()` 实现函数调用语义 2. **状态保持**:可封装内部状态(普通函数无法实现) 3. **模板支持**:支持泛型编程 ```cpp class Adder { public: int operator()(int a, int b) const { return a + b; } }; // 使用 Adder add; int sum = add(3, 5); // 输出 8 ``` #### 二、核心使用场景 1. **STL算法定制化**(最高频应用)[^1][^3] - 为 `sort`, `transform`, `for_each` 等算法提供自定义逻辑 - 示例:自定义排序规则 ```cpp // 降序排序仿函数 class DescComparator { public: bool operator()(int a, int b) const { return a > b; } }; std::vector<int> vec = {5, 2, 8, 1}; std::sort(vec.begin(), vec.end(), DescComparator()); // 结果:{8, 5, 2, 1} ``` 2. **回调机制**[^1][^5] - 替代函数指针,支持带状态的复杂回调 - 示例:事件处理器 ```cpp class EventHandler { int eventCount = 0; public: void operator()(const std::string& msg) { std::cout << "Event[" << ++eventCount << "]: " << msg << "\n"; } }; EventHandler handler; // 模拟事件触发 handler("ButtonClicked"); // 输出: Event[1]: ButtonClicked handler("DataReceived"); // 输出: Event[2]: DataReceived ``` 3. **策略模式实现**[^2] - 封装可替换的算法策略 - 示例:支付策略切换 ```cpp class PaymentStrategy { public: virtual void operator()(double amount) const = 0; }; class AlipayStrategy : public PaymentStrategy { public: void operator()(double amount) const override { std::cout << "支付宝支付:" << amount << "元\n"; } }; // 使用时注入策略 void checkout(const PaymentStrategy& pay, double amt) { pay(amt); } ``` 4. **函数适配与组合**[^4][^5] - 与 `std::bind`, `std::function` 结合实现函数组合 - 示例:参数绑定 ```cpp using namespace std::placeholders; class Multiplier { public: int operator()(int a, int b) const { return a * b; } }; Multiplier mul; auto doubleValue = std::bind(mul, _1, 2); // 绑定第二个参数 std::cout << doubleValue(5); // 输出 10 ``` #### 三、核心优势 | 特性 | 仿函数 | 普通函数 | Lambda表达式 | |---------------------|--------|----------|--------------| | 携带状态 | ✅ | ❌ | ✅ | | 内联优化 | ✅ | ❌ | ✅ | | 模板支持 | ✅ | 有限 | ✅ | | 运行时多态支持 | ✅ | ❌ | ❌ | 1. **性能优势**:编译器更容易内联优化[^3] 2. **状态封装**:通过成员变量保存调用间状态 3. **泛型能力**:模板仿函数支持任意类型 ```cpp template<typename T> class Clamp { T minVal, maxVal; public: Clamp(T min, T max) : minVal(min), maxVal(max) {} T operator()(T val) const { return std::clamp(val, minVal, maxVal); } }; Clamp<double> clamp01(0.0, 1.0); std::cout << clamp01(2.5); // 输出 1.0 ``` #### 四、典型应用场景 1. **数学运算封装**(如积分器、滤波器) 2. **条件谓词**(自定义查找/过滤条件) 3. **工厂模式**(带参数的工厂方法) 4. **线程任务**(封装复杂执行逻辑) 5. **单元测试**(模拟行为验证) > 仿函数本质是**将算法抽象为对象**,在需要灵活替换行为或维护状态的场景中,比普通函数函数指针更强大[^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值