C++函数的灵活使用

C++为了函数的灵活使用,提供了不少的语言特性以及库对函数使用的支持。 首先是语言特性的支持,其中包括函数指针和C++11中引入的lambda表达式,还有标准库对函数使用的支持,其中主要包括函数适配器,以及泛型的function,基本取代了函数指针的使用。

一、函数指针

int love(const string &s)
{
    cout<<"I love "<<s<<endl;
}

int hate(const string &s)
{
    cout<<"I hate "<<s<<endl;
}

void get_love(decltype(love) *fc,const string &s)  ///decltype将函数类型未自动转化为函数指针,而函数参数不能为函数类型,因此需要加指针修饰符
{
    fc(s);
}

 int (*fis)(const string&);
 fis = &love;  ///可将love的地址赋给fis

 fis("Hello , GNU!");

 auto lovep = love;   ///lovep 是指向love的指针

 get_love(lovep,"GCC");

 get_love(hate,"Windows");

当函数指针遇上重载的时候,auto和decltype就不能用了,编译器无法知道程序猿到底要那个函数类型,但函数指针还可以,不过必须明确指出函数指针的类型,不存在重载的函数指针。

int love(const string &s)
{
    cout<<"string "<<s<<endl;
}

int love(const string &s,unsigned ui)
{
    cout<<"int "<<ui<<" \tstring "<<s<<endl;
}

 int (*lovepx)(const string&) = love;
 int (*lovepy)(const string&,unsigned)=love;

 lovepx("Open Source");
 lovepy("To C or not to C",2);

二、lambda表达式

除了函数指针以外,C++11还引入了lambda表达式,每定义一个lambda表达式,编译器或为其生成一个内部类,同时定义该类的一个对象。

其简单的使用:

  vector<string> vs={"one","two","three","four","five","six","seven"};

  sort(vs.begin(),vs.end(),[](const string &x,const string &y){
            ///将字符串按照最后一个字母的大小排序
             return *(x.crbegin()) < *(y.crbegin());
       });

  for_each(vs.cbegin(),vs.cend(),[](const string& s){
               ///输出到标准输出
               cout<<s<<endl;
           });
  cout<<endl;

lambda表达式一般多用于在函数内部传递一些小的操作,这种情况下我们就不必定义一个函数,而直接使用lambda表达式,他的限制是,不能在函数之间共享,同时太复杂的操作也不建议使用lambda表达式。当其返回值不是太复杂,而且只有一个返回语句时,可以省略其返回值声明,由编译器根据return语句自动推导,需要返回值时,可以如下书写

vector<string> vs={"Follow","My","Heart","!","Run","Say"};

     transform(vs.cbegin(),vs.cend(),vs.begin(),[](const string &s)->string
               {
                   if(s.size() > 5)
                   {
                       return s.substr(0,5);
                   }
                   else
                   {
                       return s;
                   }
               });
    

除此之外,lambda表达式还可以共享局部变量,并且可以按值共享和按引用共享,如:

map<unsigned,string> mp={ {0,"zero"},{1,"one"},{2,"two"},
     {3,"three"},{4,"four"},{5,"five"} };

     int a=3;

    ///按值共享
     for_each(mp.cbegin(),mp.cend(),[a](const pair<unsigned,string> p)
              {
                  if(p.first > a)
                  {
                      cout<<p.first<<"\t"<<p.second<<endl;
                  }
                  else
                  {
                      cout<<p.first<<"\t"<<p.second+"!"<<endl;
                  }
              });

    int sum=0;
    vector<int> vit  = {1,2,3,4,5,6,7,8,9,0};

    ///按引用共享
    for_each(vit.cbegin(),vit.cend(),[&sum](int i)
             {
                 sum += i;
             });

    ///a按值共享,sum按引用共享
    for_each(vit.cbegin(),vit.cend(),[a,&sum](int i)
             {
                 if(i > a)
                 {
                     sum += i;
                 }
             });

    ///除了sum之外,所有的局部变量按值共享
    for_each(vit.cbegin(),vit.cend(),[=,&sum](int i)
             {
                 if(i < a)
                 {
                     sum += i;
                 }
             });

    ///除了a以外,所有的局部变量都按照引用共享
    for_each(vit.cbegin(),vit.cend(),[&,a](int i)
             {
                 if(i != a)
                 {
                     sum += i;
                 }
             });

三、关于bind

C++11中引入了bind,将原来复杂的参数绑定同一为一个接口,变得简单了

例如:

///将不小于5的元素删除
 vector<unsigned> vs={0,1,2,3,4,5,6,7,8,9,10};
 unsigned flag=5;
 vs.erase(remove_if(vs.begin(),vs.end(),
              bind(less_equal<unsigned>(),std::placeholders::_1,flag)),vs.end());
 for(const auto &item:vs)
 {
    cout<<item<<endl;
 }

其中std::placeholders::_n指的是将绑定后的函数的第n个参数传递到和bind适配器中参数出现顺序对应的绑定前函数所在位置的形参,像上面的,就是将bind后所得函数的第一个参数(由std::placeholders::_1标示),也即唯一一个参数传递到less_equal<int>的对应应顺序,即第一个参数(std::placesholders::_1是bind函数参数部分的第一个),而less_equal的第二个参数,则被绑定位flag(flag时bind函数参数部分的第二个)

利用这个特性,还可以做更有趣的事情:

///按照降序排序
 vector<unsigned> vs={0,1,2,3,4,5,6,7,8,9,10};

 sort(vs.begin(),vs.end(),
      bind(less_equal<unsigned>(),std::placeholders::_2,std::placeholders::_2));
 for(const auto &item:vs)
 {
    cout<<item<<endl;
 }

bind函数还可以用来绑定成员函数

class Boy
{
public:
    void love(const string &s)const
    {
        cout<<"I love "<<s<<endl;
    }
};

Boy by;
string dear=" beauty girl";
auto fcx = bind(&Boy::love,by,std::placeholders::_1);
auto fcy = bind(&Boy::love,std::placeholders::_1,dear);

fcx(dear);
fcy(by);

注意:bind不能用来绑定重载函数

四、关于function

function是C++11中引入的可对同类函数提供统一接口的适配器

例如:

class Boy
{
public:
    int love(const string &s)const
    {
        cout<<"I love "<<s<<endl;
    }

    int operator()(const string &s)
    {

    }
};

int love(const string &s)
{

}

Boy by;
auto lambdaf = [](const string &){return 0;};
auto bindf = bind(&Boy::love,by,std::placeholders::_1);

vector<function<int(const string&)>> vf={lambdaf,bindf,love,by};

vf[0]("Apple");
vf[1]("Google");
vf[2]("Facebook");
vf[3]("IBM");

五、关于mem_fn以及C++中成员函数作为参数传递

function<bool(const string&)> fcx = &string::empty;  ///通过传递引用来调用
function<bool(const string*)> fcxx = &string::empty; ///通过传递指针来调用

   ///既可以传递引用也可以传递指针来调用
auto fcy = mem_fn(&string::empty);
auto fcz = bind(&string::empty,std::placeholders::_1);

   vector<string> vs = {"American","China","Japan","England","Russia"};

vs.erase(remove_if(vs.begin(),vs.end(),fcy),vs.end());
copy_if(vs.begin(),vs.end(),vs.begin(),fcz);
find_if(vs.begin(),vs.end(),fcx);
时间: 2024-08-28 20:59:16

C++函数的灵活使用的相关文章

018:函数:灵活即强大

笔记 1.分清楚形参和实参 2.函数文档:是函数的一部分,于解释不同,使用help(函数名)或者 函数名__doc__可以查看到 3.关键字参数(在一个函数的参数较多的时候作用比较明显): 给参数的名字下定义,例如: def F(name,words) 如下两种引用的方法是等价的 F(A,B) = F(words=B,name=A) 4.默认参数:函数定义时为形参赋初值,函数调用时若没有传递参数,则自动使用初值 def F(name=C,words=D) 5.收集参数: def test(*pa

第 018讲:函数:灵活即强大

数: 0.形参和实参: >>> def saysomething(name, words): \\name是形参: Jenny是实参 print(name + '->' + words) >>> saysomething("jenny", "happy")jenny->heppy 1.关键字函数: >>> def saysomething(name, words): print(name + '-&g

GPS数据处理 - 字符串函数的灵活应用

题目内容: NMEA- 0183协议是为了在不同的GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA- The National Marine Electronics Associa-tion)制定的一套通讯协议.GPS接收机根据NMEA-0183协议的标准规范,将位置.速度等信息通过串口传送到PC机.PDA等 设备. NMEA-0183协议是GPS接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接

Excel高手必备的最为灵活实用的引用函数:Indirect

一.什么是Indirect函数? Indirect函数称之为间接引用函数,间接引用当然是直接引用而言的.直接引用非常简单,我在任意一个单元格输入公式:“=a1”,那么将得到A1单元格的值.而间接引用则完全不同.如果我想通过间接引用函数返回a1单元格的值,我输入的公式为:=indirect('a1',1),这样才能得到A1的值.那么间接引用的优势是是什么呢?文章开头我已经说了答案了,那就是非常灵活,大家注意到indirect函数的参数加了引号,表示是文本.既然是文本,我们就可以灵活地编辑引用地址.

C#委托与C语言函数指针及函数指针数组

C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用的时候通过指针访问这个函数. 在C语言中函数指针的申明如下: //可以理解为申明一个指着变量 Func ,它的类型是 返回Type(可以为 void )类型的参数,接收 (Type one,Type two,...)类型的//参数(可以不接受参数). Type *Func(Type one,Type

SQL 自定义函数(Function)——参数默认值

sql server 自定义函数分为三种类型:标量函数(Scalar Function).内嵌表值函数(Inline Function).多声明表值函数(Multi-Statement Function) 标量函数:标量函数是对单一值操作,返回单一值. 内嵌表值函数:内嵌表值函数的功能相当于一个参数化的视图.它返回的是一个表,内联表值型函数没有由BEGIN-END 语句括起来的函数体. 多声明表值函数:它的返回值是一个表,但它和标量型函数一样有一个用BEGIN-END 语句括起来的函数体,返回值

C++笔记(3):函数的参数和返回值

刚学C++那会,做课程设计的时候总是会去网上很找别人写好的程序来参考,那时候看到函数参数列表里各种复杂的类型和奇怪的写法就头大,后来总算是慢慢搞清楚了,在此对函数各种类型的形参以及函数的返回值进行一下总结. 1.普通形参 传递普通形参也就是值传递,传递的是实际参数的一个副本,当函数被调用时,形参复制实参,也就是说此时形参和实参的值是一样的,但形参在内存中拥有自己的地址.当函数结束时形参的生命周期终止,函数内部的操作不会影响到实参的值.经典的值交换函数代码如下: void swap1(int a,

函数中参数存在的意义

无参实现 def CPU报警邮件() #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 def 硬盘报警邮件() #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 def 内存报警邮件() #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 while True: if cpu利用率 > 90%: CPU报警邮件() if 硬盘使用空间 > 90%: 硬盘报警邮件() if 内存占用 > 80%: 内存报警邮件() 有参数的实现: def 发送邮件(邮件内容) #发送邮件提醒 连接邮

函数+装饰器+迭代器+生成器

闭包函数 闭包:定义在内网函数,包含对外部作用域而非全局作用域 范围:一个函数套用1或n个函数 from urllib.request import urlopen #urlopen模块 作用:爬网页 #闭包函数,内部get函数调用外部page函数 def page(url): #调用url def get(): #下载 return urlopen(url).read() #爬网页 return get #返回url值 baidu=page("http://www.baidu.com"