【C++11】包装器

包装器

function

std::function是一个类模板,也是一个包装器(也叫做适配器)。std::function的实例对象可以包装存储其他的可以调用对象,包括函数指针、仿函数、lambda、bind表达式等,存储的可调用对象被称为std::function的目标。

若std::function不含目标,则称它为空。调用空std::function的目标导致抛出std::bad_function_call异常。

template <class T>
class function // undefined;

template <class Ret, class... Args>
class function<Ret(Args...)>;

其中:

  • Ret:被调用函数的返回类型
  • Args…:被调用函数的形参

以上是function的原型,他被定义头文件中。std::function - cppreference.com是function的官方文件链接。

函数指针、仿函数、lambda等可调用对象的类型各不相同,std::function的优势就是统一类型,对他们都可以进行包装,这样在很多地方就方便声明可调用对象的类型,下面的第二个代码样例展示了std::function作为map的参数,实现字符串和可调用对象的映射表功能。

#include<functional>
int f(int a, int b)
{
    return a + b;
}

struct Functor
{
public:
    int operator() (int a, int b)
    {
        return a + b;
    }
};

class Plus
{
public:
    Plus(int n = 10)
        :_n(n)
    {}
    static int plusi(int a, int b)
    {
        return a + b;
    }
    double plusd(double a, double b)
    {
        return (a + b) * _n;
    }
private:
    int _n;
};

int main()
{
    // 包装各种可调用对象
    function<int(int, int)> f1 = f;
    function<int(int, int)> f2 = Functor();
    function<int(int, int)> f3 = [](int a, int b) {return a + b; };

    cout << f1(1, 1) << endl;
    cout << f2(1, 1) << endl;
    cout << f3(1, 1) << endl;

    // 包装静态成员函数
    // 成员函数要指定类域并且前面加&才能获取地址
    function<int(int, int)> f4 = &Plus::plusi;
    cout << f4(1, 1) << endl;

    // 包装普通成员函数
    // 普通成员函数还有一个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以
    function<double(Plus*, double, double)> f5 = &Plus::plusd;
    Plus pd;
    cout << f5(&pd, 1.1, 1.1) << endl;

    function<double(Plus, double, double)> f6 = &Plus::plusd;
    cout << f6(pd, 1.1, 1.1) << endl;
    cout << f6(pd, 1.1, 1.1) << endl;

    function<double(Plus&&, double, double)> f7 = &Plus::plusd;
    cout << f7(move(pd), 1.1, 1.1) << endl;
    cout << f7(Plus(), 1.1, 1.1) << endl;

    return 0;
}
  1. 逆波兰表达式求值 - 力扣(LeetCode)
// 传统方式的实现
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(auto& str : tokens)
        {
            if(str == "+" || str == "-" || str == "*" || str == "/")
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                switch(str[0])
                {
                    case '+':
                        st.push(left+right);
                        break;
                    case '-':
                        st.push(left-right);
                        break;
                    case '*':
                        st.push(left*right);
                        break;
                    case '/':
                        st.push(left/right);
                        break;
                }
            }
            else
            {
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};
//使用map射string和function的方式实现
//这种方式的最大优势之一是方便扩展,假设还有其他运算,我们增加map中的映射即可
class Solution{
public:
    int evalRPN(vector<string>& tokens){
        stack<int> st;
        map<string,function<int(int,int)>> opFuncMap={
            {"+",[](int x,int y){return x+y;}},
            {"-",[](int x,int y){return x-y;}},
            {"*",[](int x,int y){return x*y;}},
            {"/",[](int x,int y){return x/y;}}
        };
        for(auto& str : tokens)
        {
            if(opFuncMap.count(str)) // 操作符
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                int ret = opFuncMap[str](left, right);
                st.push(ret);
            }
            else
            {
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};

bind

template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);

template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);

bind是一个函数模板,它也是一个可调用对象的包装器,可以把他看做一个函数适配器,对接收的fn可调用对象进行处理后返回一个可调用对象。bind可以用来调整参数个数和参数顺序。bind也在这个头文件中。

调用bind的一般形式:auto newCallable = bind(callable,arg_list); 其中newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。

arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是占位符,表示newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。_1/_2/_3…这些占位符放到placeholders的一个命名空间中。

#include<functional>
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;

int Sub(int a, int b)
{
    return (a - b) * 10;
}

int SubX(int a, int b, int c)
{
    return (a - b - c) * 10;
}

class Plus
{
public:
    static int plusi(int a, int b)
    {
        return a + b;
    }
    double plusd(double a, double b)
    {
        return a + b;
    }
};

int main()
{
    auto sub1 = bind(Sub, _1, _2);
    cout << sub1(10, 5) << endl;

    // bind本质返回的一个仿函数对象
    // 调整参数顺序(不常用)
    // _1代表第一个实参
    // _2代表第二个实参
    //...
    auto sub2 = bind(Sub, _2, _1);
    cout << sub2(10, 5) << endl;

    // 调整参数个数 (常用)
    auto sub3 = bind(Sub, 100, _1);
    cout << sub3(5) << endl;

    auto sub4 = bind(Sub, _1, 100);
    cout << sub4(5) << endl;

    // 分别绑死第123个参数
    auto sub5 = bind(SubX, 100, _1, _2);
    cout << sub5(5, 1) << endl;

    auto sub6 = bind(SubX, _1, 100, _2);
    cout << sub6(5, 1) << endl;

    auto sub7 = bind(SubX, _1, _2, 100);
    cout << sub7(5, 1) << endl;

    // 成员函数对象进行绑死,就不需要每次都传递了
    function<double(Plus&&, double, double)> f6 = &Plus::plusd;
    Plus pd;
    cout << f6(move(pd), 1.1, 1.1) << endl;
    cout << f6(Plus(), 1.1, 1.1) << endl;

    // bind一般用于,绑死一些固定参数
    function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);
    cout << f7(1.1, 1.1) << endl;

    // 计算复利的lambda
    auto func1 = [](double rate, double money, int year)->double {
        double ret = money;
        for (int i = 0; i < year; i++)
        {
            ret += ret * rate;
        }
        return ret - money;
    };

    // 绑死一些参数,实现出支持不同年华利率,不同金额和不同年份计算出复利的结算利息
    function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3);
    function<double(double)> func5_1_5 = bind(func1, 0.015, _1, 5);
    function<double(double)> func10_2_5 = bind(func1, 0.025, _1, 10);
    function<double(double)> func20_3_5 = bind(func1, 0.035, _1, 30);

    cout << func3_1_5(1000000) << endl;
    cout << func5_1_5(1000000) << endl;
    cout << func10_2_5(1000000) << endl;
    cout << func20_3_5(1000000) << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值