zoukankan      html  css  js  c++  java
  • C++11 中function和bind以及lambda 表达式的用法

    关于std::function 的用法: 
    其实就可以理解成函数指针
    1. 保存自由函数

    void printA(int a)
    {
        cout<<a<<endl;
    }
    
    std::function<void(int a)> func;
    func = printA;
    func(2);
    

     2.保存lambda表达式

    std::function<void()> func_1 = [](){cout<<"hello world"<<endl;};
    func_1();
    

      1).std::function可以绑定到全局函数/类静态成员函数(类静态成员函数与全局函数没有区别)。

     2).绑定到类的非静态成员函数,则需要使用std::bind。

    关于std::bind 的用法: 
    看一系列的文字,不如看一段代码理解的快

    #include <iostream>
    using namespace std;
    class A
    {
    public:
        void fun_3(int k,int m)
        {
            cout<<k<<" "<<m<<endl;
        }
    };
    
    void fun(int x,int y,int z)
    {
        cout<<x<<"  "<<y<<"  "<<z<<endl;
    }
    
    void fun_2(int &a,int &b)
    {
        a++;
        b++;
        cout<<a<<"  "<<b<<endl;
    }
    
    int main(int argc, const char * argv[])
    {
        auto f1 = std::bind(fun,1,2,3); //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
        f1(); //print:1  2  3
    
        auto f2 = std::bind(fun, placeholders::_1,placeholders::_2,3);
        //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定
        f2(1,2);//print:1  2  3
    
        auto f3 = std::bind(fun,placeholders::_2,placeholders::_1,3);
        //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定
        //注意: f2  和  f3 的区别。
        f3(1,2);//print:2  1  3
    
    
        int n = 2;
        int m = 3;
    
        auto f4 = std::bind(fun_2, n,placeholders::_1);
        f4(m); //print:3  4
    
        cout<<m<<endl;//print:4  说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的
        cout<<n<<endl;//print:2  说明:bind对于预先绑定的函数参数是通过值传递的
    
    
        A a;
        auto f5 = std::bind(&A::fun_3, a,placeholders::_1,placeholders::_2);
        f5(10,20);//print:10 20
    
        std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);    在实际使用中都用 auto 关键字来代替std::function… 这一长串了。
        fc(10,20);//print:10 20
    
        return 0;
    }
    

     https://blog.csdn.net/liukang325/article/details/53668046

    lambda 表达式

    C++11中新增了lambda 表达式这一语言特性。lambda表达式可以让我们快速和便捷的创建一个”函数”。

    下面是lambda表达式的语法:

    [ capture-list ] { body }
    [ capture-list ] ( params ) { body }
    [ capture-list ] ( params ) -> ret { body }   有返回值  (ret是返回值类型)
    [ capture-list ] ( params ) mutable exception attribute -> ret { body }
    

    这其中:

    • - capture-list 是需要捕获的变量列表,用逗号分隔。其详细说明见下文。
    • - params 是lambda表达式需要的参数列表,写法和函数参数一样,不过这里不支持默认参数。
    • - ret 指明了lambda表达式的返回值。通过return语句,如果编译器能够推断出返回值的类型。或者表达式没有返回值,“-> ret”可以省略。
    • - body 函数体。
    • - mutable 当捕获列表是以复制(见下文)的形式捕获时,默认这些复制的值是const的,除非指定了mutable。
    • - exception 提供了异常的说明。
    • - attribute 对于attribute的描述可以参见这里:http://en.cppreference.com/w/cpp/language/attributes,这里不多说明。

    下面,我们通过经典的Hello World示例来看一下lambda表达式:

    auto lambda1 = [] {std::cout << "Hello, World!
    ";};
    lambda1();
    

    这个lambda表达式将打印出字符串“Hello, World!”。

    同时,我们将这个表达式赋值给“lambda1”这个变量,然后像调用函数一样,调用这个lambda表达式。

    使用lambda表达式,可以让我们省却定义函数的麻烦,以inline的方式写出代码,这样的代码通常更简洁。 并且,由于阅读代码时不用寻找函数定义,这样的代码也更易读。

    下面,我们来看另外一个例子。这个例子的需求是:

    分两次,打印出一个vector集合中,所有:

    1. 模 5 = 0

    2. 大于 20

    的数字。

    现假设已有这个集合的定义如下:

    vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 };

    我们最先想到的方法自然是定义两个函数,分别按照上面的要求打印出需要的数字,它们的定义如下:

    void printNumber1(vector<int>& numbers) {
     for (const int& i : numbers) {
     if (i % 5 == 0) {
     cout<<i<<endl;
     }
     }
    }
    
    void printNumber1(vector<int>& numbers) {
     for (const int& i : numbers) {
     if (i % 5 == 0) {
     cout<<i<<endl;
     }
     }
    }
    

     然后,我们在需要的地方,调用它们:

    printNumber1(numbers);
    printNumber2(numbers);

    这里逻辑上并没有问题,但是:

    1. 这里我们必须先定义这个函数,才能使用。而这样的函数,可能实际上我们只会使用一次。

    2. 当工程大到一定程度,我们可能不记得每个函数的实现(所以函数命名很重要,原谅我这里给函数起了很含糊的名字,你在实际上工程中,请不要这样做),为了知道每个函数的实现,我们不得不查看函数的定义,这无疑给代码的阅读造成了一定的麻烦。

    下面,我们来看看使用lambda表达式如何改善上面说的问题。

    使用lambda表达式,我们可以这样写:

    for_each(numbers.begin(), numbers.end(), [] (int i) {
     if(i % 5 == 0) {
     cout<<i<<endl;
     }
    });
    
    for_each(numbers.begin(), numbers.end(), [] (int i) {
     if(i > 20) {
     cout<<i<<endl;
     }
    });
    

    这里,我们不用单独定义函数,直接以inline的方式解决了问题。并且,这段代码一气呵成,你很直观的看到了执行的逻辑。

    下面,我们再详细看一下lambda表达式中的捕获列表的语法,它可能是以下几种情况中的一种:

    • [] 不捕获任何变量
    • [&] 以引用的方式捕获所有变量
    • [=] 以复制的方式捕获所有变量
    • [=, &foo] 以引用的方式捕获foo变量,但是以复制的方式捕获其他变量
    • [bar] 以复制的方式捕获bar变量,不再捕获任何其他变量
    • [this] 捕获this指针

    下面,我们再以一个例子说明捕获列表的用法。

    这里,我们的需求是:

    打印出一个vector<int>的所有数字之和

    同样的,我们先以函数的方式来解决这个问题,这个函数的定义可以是这样的:

    void printSum(vector<int>& numbers) {
     int sum = 0;
     for (const int& i : numbers) {
     sum += i;
     }
     cout<<sum<<endl;
    }
    

     然后,我们在需要的地方调用这个函数:

    vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 };
    printSum (numbers);
    

     而假设我们用lambda表达式来写,这样写就可以了:

    vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 };
    int sum = 0;
    std::for_each(numbers.begin(), numbers.end(), [&sum] (const int& i) { sum += i;});
    cout<<sum<<endl;
    

     这里,我们用 [&sum]以引用的形式捕获了sum这个变量,并且在lambda表达式中修改了这个变量。

    这样写,是不是比定义函数的方式简洁了很多?

    对于这种,能够捕获其定义时上下文变量的函数,我们称之为“闭包”,下文还将提到。

    http://www.jb51.net/article/104376.htm

  • 相关阅读:
    桥牌笔记:三个输墩压缩为一个
    读书笔记2013第7本:《杠杆阅读术》
    读书笔记2013第6本:《棋与人生》(一)
    《Two Dozen Short Lessons in Haskell》(二十)分数
    《Two Dozen Short Lessons in Haskell》学习(十八) 交互式键盘输入和屏幕输出
    Exercise: A Routine Day
    读书笔记2013第6本:《棋与人生》(二)
    读书笔记2013第8本:《超级快速阅读》
    TC的房子
    [转贴]Windows批处理调用程序后如何自动退出
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4200969.html
Copyright © 2011-2022 走看看