栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++ 基础与深度分析 Chapter10 泛型算法(bind、lambada表达式、泛型算法的改进ranges)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++ 基础与深度分析 Chapter10 泛型算法(bind、lambada表达式、泛型算法的改进ranges)

文章目录
  • 概述
  • bind
  • lambada表达式
  • lambada表达式的深入应用
  • 泛型算法的改进ranges

概述


很多算法允许通过可调用对象自定义计算逻辑的细节

transform





如何定义可调用对象:

  • 函数指针:概念直观,但定义位置受限

    c++不支持在函数内部定义函数,所以位置是受限的。

  • 类:功能强大,但书写麻烦
    通过操作符重载,为类定义可调用对象。

  • bind :基于已有的逻辑灵活适配,但描述复杂逻辑时语法可能会比较复杂难懂

  • lambda 表达式:小巧灵活,功能强大

bind




#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

bool MyPredict2(int val1, int val2)
{
    return val1 > val2;
}
int main()
{
    using namespace std::placeholders;
    std::vector x{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector y{};
    std::copy_if(x.begin(), x.end(), std::back_insert_iterator(y), std::bind(MyPredict2, _1, 3));
    for (auto p : y)
    {
        cout << p << ' '; // 4-10
        cout << endl;
    }
}
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

bool MyPredict2(int val1, int val2)
{
    return val1 > val2;
}
int main()
{
    using namespace std::placeholders;
    auto x = std::bind(MyPredict2, _1, 3); // _1代表调用x时,接收x的第1个参数
    x(50); // 50会作为MyPredict2的第1个参数
    cout << x(50) << endl; // 1 true
}



#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

bool MyPredict2(int val1, int val2)
{
    return val1 > val2;
}

bool MyAnd(bool val1, bool val2)
{
    return val1 && val2;
}
int main()
{
    using namespace std::placeholders;
    auto x1 = std::bind(MyPredict2, _1, 3); 
    auto x2 = std::bind(MyPredict2, 10, _1); 
    auto x3 = std::bind(MyAnd, x1, x2);
    cout << x3(5) << endl; // 1 意思为:3 < 5 < 10
}

调用 std::bind 时,传入的参数会被复制,这可能会产生一些调用风险
用智能指针解决

可以使用 std::ref 或 std::cref 避免复制的行为

bind还有一个缺点,就是复杂逻辑很难看懂代码。

std::bind_front ( C++20 引入): std::bind 的简化形式
绑定第一个参数。

lambada表达式




参数与函数体:

int main()
{
    auto x = [](int val) { return val > 3; }; // (函数形参) {函数体,多条语句,要用分号隔离}
    cout << x((5)) << endl; // 1, 5 > 3
}
int main()
{
    auto x = [](int val) { return (val > 3) && (val < 10); }; 
    cout << x((5)) << endl; // 1
}


返回类型的自动推导c++11。如果引入更多的return语句,所有的return语句的类型必须是相同的,这是前提。

int main()
{
    auto x = [](int val) 
    {
        if (val > 3)
        {
            return 3.0;
        }
        else
        {
            return 1.5;
        }
    
    }; 
    cout << x((5)) << endl; // 3,自动推导x的类型是double
}
int main()
{
    // 告诉编译器返回类型
    auto x = [](int val) -> float 
    {
        if (val > 3)
        {
            return 3.0;
        }
        else
        {
            return 1.5f;
        }
    
    }; 
    cout << x((5)) << endl; // 3
}

捕获: 针对函数体中使用的局部自动对象进行捕获

int main()
{
    int y = 10;

    auto x = [](int val)
    {
        return val > y; // 报错,在lambada表达式内部,不知道y是什么
    }; 
    cout << x((5)) << endl; 
}
int main()
{
    int y = 10; // 局部自动对象

    auto x = [y](int val)
    {
        return val > y; // 把y放到[]内进行捕获
    }; 
    cout << x((5)) << endl; 
}
int main()
{
    static int y = 10; // y是一个局部静态对象,不需要捕获,直接使用

    auto x = [](int val)
    {
        return val > y; 
    }; 
    cout << x((5)) << endl; 
}

值捕获

int main()
{
    int y = 10;

    auto x = [y] (int val) mutable
    {
        ++y;
        return val > y; 
    }; 
    cout << x((5)) << endl; 
    cout << y << endl; // 10 lambada对y的修改,不会传递到外部,因为是值捕获,y是复制到lambada内部
}

引用捕获

int main()
{
    int y = 10;

    auto x = [&y] (int val)
    {
        ++y;
        return val > y; 
    }; 
    cout << x((5)) << endl; 
    cout << y << endl; // 11 y是引用捕获
}

混合捕获

int main()
{
    int y = 10;
    int z = 3;

    // 对y进行引用捕获,对z进行值捕获 --> 混合捕获
    auto x = [&y, z] (int val) mutable 
    {
        ++y;
        return val > z; 
    }; 
    cout << x((5)) << endl; // 1
    cout << y << endl; // 11
}

如果lambada[捕获列表]里要捕获的值太多,这样就比价麻烦。大部分对象如果都是值捕获的,我们在[]里写个=。所有在{}使用的局部自动对象都值捕获了。我们也可以在[]中写入&,表示在{}使用的局部自动对象都引用捕获了。

int main()
{
    int y = 10;
    int z = 3;

    // []除了z是值捕获,其他都是引用捕获
    auto x = [&, z] (int val) mutable 
    {
        ++y;
        return val > z; 
    }; 
    cout << x((5)) << endl; 
    cout << y << endl; 
}

this 捕获

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

struct Str{
    auto fun()
    {
        int val = 3; // 局部自动对象
        // this 表示如果构造了Str对象,this就是一个指针,指向Str对象的地址
        auto lam = [val, this] ()  
        {
            return val > x;
        }; 
        return lam();
    }
    int x;
};

int main()
{
    Str s;
    s.fun();
}

初始化捕获( C++14 )

int main()
{
    int x = 3;
    // 初始化捕获,构造对象y,将x赋予y
    auto lam = [y = x](int val)
    {
        return val > y;
    };
    cout << lam(100) << endl;
}

int main()
{
    int x = 3;
    int y = 10;
    // z是在编译期计算出来的
    auto lam = [z = x + y](int val)
    {
        return val > z;
    };
    cout << lam(100) << endl;
}

*this 捕获( C++17 )

说明符
mutable

int main()
{
    int y = 3;
    auto lam = [y](int val) mutable
    {
        ++y; // 不能通过编译,除非加上mutable
        return val > y;
    };
}

constexpr (C++17)

int main()
{
    int y = 3;
    auto lam = [y](int val) constexpr
    {
        return val + 1; // 表示这个lam可以在编译期进行调用
    };
    constexpr int val = lam(100);
    cout << val << endl;
}

consteval (C++20)

int main()
{
    int y = 3;
    auto lam = [y](int val) consteval
    {
        return val + 1; // consteval只能在编译期调用
    };
    constexpr int val = lam(100);
    cout << val << endl;
}
lambada表达式的深入应用


捕获时计算

int main()
{
    int x = 3;
    int y = 5;
    // 捕获时计算
    auto lam = [z = x + y]()
    {
        return z;
    };
    lam();
}

即调用函数表达式( Immediately-Invoked Function Expression, IIFE )

int main()
{
    int x = 3;
    int y = 5;
    // 捕获时计算
    const auto val = [z = x + y]()
    {
        return z;
    }(); // 即调用函数表达式( Immediately-Invoked Function Expression, IIFE )
    // 构造完lam,构造完,马上执行lam 表达式
    // 执行完的值,马上赋给val,不需要额外定义函数
}

使用 auto 避免复制( C++14 )

int main()
{
    auto lam = [](auto x)
    {
        return x + 1;
    };
}
int main()
{
    std::map m{{2, 3}};
    // 虽然用了引用,但是还是复制了
    auto lam = [](const std::pair& p)
    {
        return p.first + p.second;
    };
    cout << lam(*m.begin()) << endl; // 5
}
int main()
{
    std::map m{{2, 3}};
    auto lam = [](const auto& p)
    {
        return p.first + p.second;
    };
    cout << lam(*m.begin()) << endl; // 5
}

Lifting ( C++14 )

#include 
#include 
using namespace std;

auto fun(int val)
{
    return val + 1;
}

auto fun(double val)
{
    return val + 1;
}

int main()
{
    // auto x,来决定用哪个fun
    auto lam = [](auto x)
    {
        return fun(x);
    };
    cout << lam(3) << endl; // 4
    cout << lam(3.5) << endl; // 4.5
    // auto b = std::bind(fun, 3); // bind不知道调用哪个fun了
    // cout << b() << endl;
}

递归调用( C++14 )

#include 
#include 
using namespace std;



int main()
{
    // 这么写递归调用的lambada表达式会报错
    auto factorial = [](int n){
        return n > 1 ? n * factorial(n - 1) : 1;
    };
    cout << factorial(5) << endl; // 120
}
泛型算法的改进ranges

#include 
#include 
#include 
#include 
using namespace std;


int main()
{
    std::vector x{1, 2, 3, 4, 5};
   //  auto it = std::ranges::find(x.begin(), x.end(), 3);
    auto it = std::ranges::find(x, 3);
    cout << *it << endl;
}


view并不是对输入的东西立即计算,而是需要的时候计算,把提升程序的性能。view模糊了容器和算法的概念了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/997132.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号