jjzjj

3.C++11中引入的bind绑定器和function函数对象

woden3702 2023-03-28 原文

绑定器bind1st,bind2nd

vector<int> vec;
for(int i=0;i<20;i++){
    vec.push_back(rand()%100);
}
showContainer(vec);

sort(vec.begin(),vec.end(),greater<int>());
showContainer(vec);
/*
 * greater  a>b
 * less     a<b
 * */
//把70按顺序插入到vector容器中
auto it= find_if(vec.begin(), vec.end(), bind1st(greater<int>(),70));//两种绑定器的用法
//auto it= find_if(vec.begin(), vec.end(), bind2nd(less<int>(),70));
if(it!=vec.end()){
    vec.insert(it,70);
}
showContainer(vec);

绑定器的实现原理

绑定器其实是函数对象的一个应用!!绑定器+二元函数对象+值=一元函数对象。底层还是靠二元函数对象做事

自己实现一个绑定器:

/**
 * 
 * @tparam Compare 函数对象类型
 * @tparam T 对象类型
 */
template<typename Compare,typename T>
class CMyBind1st{
public:
    CMyBind1st(Compare com,T val):_comp(com),_val(val){}
    /**
     * 绑定器函数对象的实现,实际上是传入的函数对象在干活
     * @param second 传入要绑定的数据
     * @return 函数对象,这个函数对象干完传回的数据
     */
    bool operator()(const T &second){
        return _comp(_val,second);
    }
private:
    Compare _comp;
    T _val;
};
/**
 * 实现绑定器
 * @tparam Compare 返回函数对象类型
 * @tparam T 数据对象
 * @param comp 函数对象
 * @param val 绑定数据
 * @return 
 */
template<typename Compare,typename T>
CMyBind1st<Compare,T> my_bind1st(Compare comp,const T &val){
    return CMyBind1st<Compare,T>(comp,val);
}

/**
 *
 * @tparam Compare 函数对象类型
 * @tparam T 对象类型
 */
template<typename Compare,typename T>
class CMyBind2nd{
public:
    CMyBind2nd(Compare com,T val):_comp(com),_val(val){}
    /**
     * 绑定器函数对象的实现,实际上是传入的函数对象在干活
     * @param second 传入要绑定的数据
     * @return 函数对象,这个函数对象干完传回的数据
     */
    bool operator()(const T &first){
        return _comp(first,_val);
    }
private:
    Compare _comp;
    T _val;
};
/**
 * 实现绑定器
 * @tparam Compare 返回函数对象类型
 * @tparam T 数据对象
 * @param comp 函数对象
 * @param val 绑定数据
 * @return 返回的是一个函数对象
 */
template<typename Compare,typename T>
CMyBind2nd<Compare,T> my_bind2nd(Compare comp,const T &val){
    return CMyBind2nd<Compare,T>(comp,val);
}
/////////////////
/**
 * 实现find_if
 * @tparam Iterator 迭代器
 * @tparam Compare 函数对象
 * @param begin 
 * @param end 
 * @param comp 函数对象
 * @return 迭代器
 */
template<typename Iterator,typename  Compare>
Iterator my_find_if(Iterator begin,Iterator end,Compare comp){
    for(;begin!=end;++begin){
        if(comp(*begin)){//comp.operator()(*begin)
            return begin;
        }
    }
    return end;
}

function函数对象的应用

首先讲一下什么是函数指针

如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。

那么这个指针变量怎么定义呢?虽然同样是指向一个地址,但指向函数的指针变量同我们之前讲的指向变量的指针变量的定义方式是不同的。例如:

int(*p)(int, int);

这个语句就定义了一个指向函数的指针变量 p。首先它是一个指针变量,所以要有一个“”,即(p);其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。p 的类型为 int(*)(int,int)。

所以函数指针的定义方式为:函数返回值类型 (* 指针变量名) (函数参数列表);

函数指针的使用:

int Func(int x);   /*声明一个函数*/
int (*p) (int x);  /*定义一个函数指针*/
p = Func;          /*将Func函数的首地址赋给指针变量p*/
# include <stdio.h>
int Max(int, int);  //函数声明
int main(void)
{
    int(*p)(int, int);  //定义一个函数指针
    int a, b, c;
    p = Max;  //把函数Max赋给指针变量p, 使p指向Max函数
    printf("please enter a and b:");
    scanf("%d%d", &a, &b);
    c = (*p)(a, b);  //通过函数指针调用Max函数
    printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
    return 0;
}
int Max(int x, int y)  //定义Max函数
{
    int z;
    if (x > y)
    {
        z = x;
    }
    else
    {
        z = y;
    }
    return z;
}

输出结果是:
please enter a and b:3 4
a = 3
b = 4
max = 4

function:

void hello1(){
    cout<<"hello1"<<endl;
}

void hello2(string str){
    cout<<str<<endl;
}

int sum(int a,int b){
    return a+b;
}

class TT{
public:
    TT()=default;
    void hello(string str) const {
        cout<<"call TT::hello"<<str<<endl;
    }
};

int main(){

    function<void()> func1=hello1;
    function<void(string)> func2=hello2;

    func1();
    func2("sashkgf");

    function<int(int,int)> func3=sum;

    cout<<func3(20,22)<<endl;

    function<void(TT*,string)> func4=&TT::hello;
    TT t;
    func4(&t,"asgasgxb");

    return 0;
}

使用function需要注意两点:

  1. 用函数类型实例化function
  2. 通过function调用operator()函数的时候,需要根据函数类型传入相应的参数

一个function应用的例子:

void doShow(){cout<<"查看所有书籍"<<endl;}
void doBorrow(){cout<<"借书"<<endl;}
void doBack(){cout<<"还书"<<endl;}
void doQuery(){cout<<"查询书籍"<<endl;}
void doLogout(){cout<<"注销"<<endl;}


int main(){

    int choice=0;
    map<int,function<void()>> actionMap;
    actionMap.insert({1,doShow});
    actionMap.insert({2,doBorrow});
    actionMap.insert({3,doBack});
    actionMap.insert({4,doQuery});
    actionMap.insert({5,doLogout});

    for(;;){
        cout<<"————————————————————"<<endl;
        cout<<"1_查看所有书籍"<<endl;
        cout<<"2_借书"<<endl;
        cout<<"3_还书"<<endl;
        cout<<"4_查询书籍"<<endl;
        cout<<"5_注销"<<endl;
        cout<<"————————————————————"<<endl;
        cin>>choice;
        auto it= actionMap.find(choice);
        if(it==actionMap.end()){
            cout<<"输入数字无效,请重新选择"<<endl;
        }else{
            it->second();
        }

    }
    return 0;
}

输出:


1_查看所有书籍
2_借书
3_还书
4_查询书籍
5_注销


4
查询书籍

如何实现function

首先介绍两个前置知识:

模板的完全特例化和非完全特例化

模板的实参推演

实现function

template<typename Fty>//必须要有
class MyFunction{};

template<typename R,typename... A>//非完全特例化
class MyFunction<R(A...)>{//function其实就是函数指针的封装
public:
    using PFUNC=R(*)(A...);//函数指针
    MyFunction(PFUNC pfunc):_pfunc(pfunc){}
    R operator()(A... arg){
        return _pfunc(arg...);
    }
private:
    PFUNC _pfunc;
};

int main(){
    MyFunction<void(string)> func2=hello2;

    func2("sashkgf");

    MyFunction<int(int,int)> function= sum;
    cout<<function(20,30)<<endl;
    return 0;
}

使用bind和function实现线程池

C++11里的绑定器bind返回的还是是一个函数对象

//TODO 学完线程再回来写这个笔记

lambda表达式

lambda表达式的语法:[捕获外部变量](形参列表)->返回值{操作代码}

如果lambda表达式的返回值不需要,那么->返回值可以省略

[捕获外部变量]

lambda表达式生成的函数对象的()重载默认是const常量形的,不能对内部的值进行修改,需要在lambda表达式的后面加mutable标识符才可以修改(只有是传值的情况下需要加这个标识符)。如果是[&]的情况就不需要加这个标识符

使用lambda表达式实现优先级队列:

class Data{
public:
    Data(int val1=10,int val2=10):ma(val1),mb(val2){}
    int ma;
    int mb;
};
int main(){
    using FUNC=function<bool(Data&,Data&)>;
    priority_queue<Data,vector<Data>,FUNC> que([](Data& d1,Data& d2)->bool{//在构造函数中使用lambda表达式传入函数对象
        return d1.ma>d2.ma;
    });
    que.push({10,20});
    que.push({20,10});
    que.push({30,40});

    return 0;
}

有关3.C++11中引入的bind绑定器和function函数对象的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  4. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  5. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  6. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  7. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  8. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  9. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  10. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

随机推荐