C++高级特性:柯里化过程与std::bind(六)

1、柯里化过程
1.1、operator()的引入

现在需要完成这样一个需求:有一个函数每次调用返回的结果不一样。例如:两次调用的返回值都不一样那么就可以达到这种目的

1.1.1、简单点的写法

可以给一个全局的变量(静态变量),每次调用对这个全局变量进行值的修改然后返回,这样每次返回都不一样。

cpp 复制代码
#include <iostream>
int nums;
int func()
{
    return ++nums;
}

int main() {
    std::cout << "Hello, World!" << std::endl;
    std::cout << std::boolalpha << (func() == func()) << std::endl;
    return 0;
}
1.1.2、operator()重载

如果需要用类来完成,那么可以使用operator()仿函数来做,仿函数其实是一个特殊的函数。

cpp 复制代码
class Functor{
public:
    int x;
    int operator()(){
        return ++x;
    }
};
void test2()
{
    Functor func;
    std::cout << std::boolalpha << (func() == func()) << std::endl;
}
1.2、Chain Adding

有了上面的基础,可以看这样一个题目:

  • 打算创建一个函数,这个函数能够完成类似于add(1) = 1、add(1)(2) = 3、add(1)(2)(3) = 6...类似于这种求和的操作。
  • 并且能够判断出add(1) == 1这种判断也能完成,以及add(1) + 3、add(1) - 3
  • 意思没出现一个括号就会对之前的值进行一个加法和减法

通过分析可以看到add(1)应该返回一个类似函数的东西func,然后这个东西还可以继续func(2)...可以尝试使用上面的仿函数来继续,

  • 很明显这里有一个链式编程 的东西,返回的东西应该是一个类对象本身的引用这样就可以继续链式,当然也可以返回一个普通类型但是要做好拷贝构造。
  • 对于不同类型的比较,那么肯定需要重载一下==符号进行判断值是否相等即可。
  • 对于第三个操作很明显需要重载加减法么,一样需要注意返回引用或者拷贝构造的对象。
  • 思考:如果需要流输出类对象应该怎么做呢?答案:重载输出流
  • 补充:其实还可以把类型进行重载,把当前类中的返回类型重载为int可以直接省略判断、加减和输出操作
cpp 复制代码
class Functor{
public:
    int sum;
    Functor(): sum(0){

    }
    Functor(int x): sum(x){
        
    }
    Functor& operator()(int val){
        this->sum += val;
        return *this;
    }
    bool operator== (const int x) const{
        return sum == x;
    }
    Functor& operator-(int x){
        this->sum -= x;
        return *this;
    }
    Functor& operator+(int x){
        this->sum += x;
        return *this;
    }
    friend std::ostream & operator<<(std::ostream& out, const Functor& functor){
        out << functor.sum << std::endl;
        return out;
    }
//    operator int() {							//可以直接替换 == 重载、 加减法、输出流
//        return this->sum;
//    }
};

int main()
{
    Functor f1;
    f1(1);
    std::cout << f1.sum << std::endl;
    Functor f2;
    f2(1)(2);
    std::cout << f2.sum << std::endl;
    Functor f3;
    std::cout << std::boolalpha << (f3(1) == 1)<< std::endl;

    Functor f4(1);
    f4 = f4 - 2;
    f4 = f4 + 5;
    std::cout << f4.sum << std::endl;
    std::cout << f4 << std::endl;
    return 0;
}

其实这是一个很好的例子,可以帮助我们理解重载的意义和C++面向对象的灵活使用。

1.3、柯里化过程

其实上面的链式编程或者函数式编程就是一个柯里化的过程,其实这种操作在lambda表达式也有体现的,lambda表达式中继续lambda表达式

cpp 复制代码
// add(1, 2)     -->   add(1)(2)
void test4()
{
    auto add = [](int x)->auto{
        return [x](int y) -> auto{
            return x + y;
        };
    };
    std::cout << add(1)( 2) << std::endl;
}
2、std::bind
  • 有了上面函数式编程和柯里化的过程,理解bind就很简单了。
  • std::bind主要用于给函数进行参数绑定的
cpp 复制代码
#include <iostream>
#include <functional>

int add(int a, int b)
{
    std::cout << "a = " << a << ", b = " << b <<std::endl;
    return a + b;
}
int main()
{
    using namespace std::placeholders;
    auto f1 = std::bind(add, 1, _1);
    std::cout << f1(2) << std::endl;

    auto f2 = std::bind(add, _1, 1);
    std::cout << f2(2) << std::endl;

    std::cout << std::bind(add, 1, _1)(2) << std::endl;
    std::cout << std::bind(add, _1, _2)(3, 4) << std::endl;
    std::cout << std::bind(add, _2, _1)(3, 4) << std::endl;
    std::cout << std::bind(add, _1, _1)(3, 4) << std::endl;
    std::cout << std::bind(add, _2, _2)(3, 4) << std::endl;

    // C++20标准
//    std::cout << std::bind_front(add, 1)(2) << std::endl;
    // C++23标准
//    std::cout << std::bind_back(add, 2)(1) << std::endl;
    return 0;
}
  • 为了给bind参数绑定需要引入命名空间中的using name std::placeholders占位符宏
  • 通过_i来表示第几个参数,其中最明显的是一绿框和黑框中的
    • 绿框:根据传入的占位符宏的编号索引到对应的值,_2表示取参数列表的第2个参数、依次类推
    • 黑框:当参数列表为X个时,可以使用的宏为_i <= X,同时可以多个参数绑定同一个宏
  • 和std::move一样可能现在对这个概念还不是很熟悉,等到完美转发forward的时候会更加清楚的理解bind和move
相关推荐
猷咪5 分钟前
C++基础
开发语言·c++
IT·小灰灰7 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧9 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q9 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳09 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾9 分钟前
php 对接deepseek
android·开发语言·php
CSDN_RTKLIB12 分钟前
WideCharToMultiByte与T2A
c++
2601_9498683613 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计27 分钟前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
蒹葭玉树38 分钟前
【C++上岸】C++常见面试题目--操作系统篇(第二十八期)
linux·c++·面试