代码简洁之道:C++ 11 之auto+ for_each + lamda表达式

摘要:在很多中情况下,我们需要这样的运算:给vector中每个元素进行相似的处理(每个元素+1,或者其他).一般情况下,我们会选用for循环,然后然后对每个元素进行处理。实际上,C++ 11提供了了lamda表达式,结合for_each,可以写出更加简洁和高效的代码。

1.for_each.简介

for_each是C++中的模板,具体用法可以参考这里:http://www.cplusplus.com/reference/algorithm/for_each/

2.lamda表达式

lamda表达式,在python中也有,简单地说就是匿名函数。关于lamda表达式的例子和详细用法,我们可以参考这:http://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B

C++11提供了对匿名函数的支持,称为Lambda函数(也叫Lambda表达式). Lambda表达式具体形式如下:

    [capture](parameters)->return-type{body}

capture:需要用到的外部变量,parameters:函数参数;body:函数体

  如果没有参数,空的圆括号()可以省略.返回值也可以省略,如果函数体只由一条return语句组成或返回类型为void的话.形如:

     [capture](parameters){body}

  下面举了几个Lambda函数的例子:      

[](int x, int y) { return x + y; } // 隐式返回类型

[](int& x) { ++x; }   // 没有return语句 -> lambda 函数的返回类型是‘void‘

[a](int& x) { x+=a; }   // 没有return语句 -> lambda 函数的返回类型是‘void‘;注意,此处a是从lambda函数体外部传入其中的变量

[]() { ++global_x; }  // 没有参数,仅访问某个全局变量

[]{ ++global_x; }     // 与上一个相同,省略了()

  可以像下面这样显示指定返回类型:

[](int x, int y) -> int { int z = x + y; return z; }

  在这个例子中创建了一个临时变量z来存储中间值. 和普通函数一样,这个中间值不会保存到下次调用. 什么也不返回的Lambda函数可以省略返回类型, 而不需要使用 -> void 形式.

  Lambda函数可以引用在它之外声明的变量. 这些变量的集合叫做一个闭包. 闭包被定义在Lambda表达式声明中的方括号[]内. 这个机制允许这些变量被按值或按引用捕获.下面这些例子就是:

[]        //未定义变量.试图在Lambda内使用任何外部变量都是错误的.
[x, &y]   //x 按值捕获, y 按引用捕获.
[&]       //用到的任何外部变量都隐式按引用捕获
[=]       //用到的任何外部变量都隐式按值捕获
[&, x]    //x显式地按值捕获. 其它变量按引用捕获
[=, &z]   //z按引用捕获. 其它变量按值捕获

  接下来的两个例子演示了Lambda表达式的用法.

std::vector<int> some_list;
int total = 0;
for (int i=0;i<5;++i) some_list.push_back(i);
std::for_each(begin(some_list), end(some_list), [&total](int x)
{
    total += x;
});

  此例计算list中所有元素的总和. 变量total被存为lambda函数闭包的一部分. 因为它是栈变量(局部变量)total的引用,所以可以改变它的值.

std::vector<int> some_list;
  int total = 0;
  int value = 5;
  std::for_each(begin(some_list), end(some_list), [&, value, this](int x)
  {
    total += x * value * this->some_func();
  });

  此例中total会存为引用, value则会存一份值拷贝. 对this的捕获比较特殊, 它只能按值捕获. this只有当包含它的最靠近它的函数不是静态成员函数时才能被捕获.对protect和priviate成员来说, 这个lambda函数与创建它的成员函数有相同的访问控制. 如果this被捕获了,不管是显式还隐式的,那么它的类的作用域对Lambda函数就是可见的. 访问this的成员不必使用this->语法,可以直接访问.

  不同编译器的具体实现可以有所不同,但期望的结果是:按引用捕获的任何变量,lambda函数实际存储的应该是这些变量在创建这个lambda函数的函数的栈指针,而不是lambda函数本身栈变量的引用. 不管怎样, 因为大数lambda函数都很小且在局部作用中, 与候选的内联函数很类似, 所以按引用捕获的那些变量不需要额外的存储空间.

  如果一个闭包含有局部变量的引用,在超出创建它的作用域之外的地方被使用的话,这种行为是未定义的!

  lambda函数是一个依赖于实现的函数对象类型,这个类型的名字只有编译器知道. 如果用户想把lambda函数做为一个参数来传递, 那么形参的类型必须是模板类型或者必须能创建一个std::function类似的对象去捕获lambda函数.使用 auto关键字可以帮助存储lambda函数,

3.auto

auto可以让编译器自动推断变量类型,例如:

vector<vector<int> > func(int a, int b);
auto func(2,2);

4.例子leetcode上面有一道题,产生全排列

class Solution {
public:
    vector<vector<int> > permuteUnique(vector<int> &num) {
        vector<vector<int> > result;
        vector<int> empty;
        int n=num.size();
        if(n==0){
            result.push_back(empty);
            return result;
        }
        vector<int> last(num.begin()+1, num.end());
        auto pre=permuteUnique(last);
        for(int i=0;i<n;i++){
            for_each(pre.begin(), pre.end(), [n, num, i, &result](vector<int> line){
                            line.insert(line.begin()+i, num[0]);
                            result.push_back(line);
                    });
        }
        return result;
    }
};  

代码简洁之道:C++ 11 之auto+ for_each + lamda表达式

时间: 2024-08-06 02:27:21

代码简洁之道:C++ 11 之auto+ for_each + lamda表达式的相关文章

代码简洁之道——类

(1)类的组织:一般排列顺序公共静态变量.私有静态变量.私有实体变量.公共函数.公共函数调用的私有工具(函数) (2)类应该短小: 单一权责原则:类或模块只有一条加以修改的理由: 内聚:方法操作的变量也多,内聚性就越高: 保持内聚性就会得到许多短小的类 (3)为了修改而组织:对类加以组织,减低修改的风险 隔离修改:借住接口和抽象类来隔离修改细节带来的影响 DIP 依赖导致原则,类应当依赖于抽象而不是依赖于具体细节 代码简洁之道--类

代码简洁之道 判断篇

javascript 简洁之道 判断篇 第一个例子 if (state === 1) { return true } else if (state === 2) { return true } else if (state === 3) { return true } else if (state === 4){ return true } else { return false } 你首先想到的可能是 使用 switch case switch (state) { case 1: return

代码简洁之道(判断篇)

第一个例子 if (state === 1) { return true } else if (state === 2) { return true } else if (state === 3) { return true } else if (state === 4){ return true } else { return false } 你首先想到的可能是 使用 switch case, 我们使用 switch case 来改写它: switch (state) { case 1: re

代码简洁之道(1)-年份

1.说明 本文是在阅读一些好的框架的源码时看到的,在此做个记录. 2.具体内容 2.1判断年份是否是闰年 2.1.1前言 为什么会有闰年? 若以陽曆為例,「年」的計算基礎是回歸年,而一個回歸年大約等於365.24220日.因為在平年西曆只計算365日,結果四年後便會累積0.24220×4=0.9688日,大約等於一日,所以便逢四年增加一日閏日以抵銷這0.9688日. 然而,累積4年後多的0.96876天,與真正的1日尚差0.03124天,故如果不間斷地按照4年1閏的方式修正,百年後將累積成365

PHP代码简洁之道——SOLID原则

SOLID 是Michael Feathers推荐的便于记忆的首字母简写,它代表了Robert Martin命名的最重要的五个面对对象编码设计原则 S: 单一职责原则 (SRP) O: 开闭原则 (OCP) L: 里氏替换原则 (LSP) I: 接口隔离原则 (ISP) D: 依赖反转原则 (DIP) 单一职责原则 Single Responsibility Principle (SRP) "修改一个类应该只为一个理由".人们总是易于用一堆方法塞满一个类,如同我们在飞机上只能携带一个行

代码简洁之道与重构

函数篇: 1.函数的功能要单一. 2.函数要短小,  20行封顶最佳. 3.函数参数, 最理想的参数数虽是0,其次是1,再次是2,有足够的理由才能使用三个以上参数.(建议:参数较多时就对参数进行封装) 4.使用异常替代返回错误码.(错误码的处理在代码中非常重要的) 5.函数别重复自己 ,可以把公共的部分封装成接口.

C++11学习笔记之三lamda表达式,std::function, std::bind

//lamda //first lamda [] {}; // second lamda []() //or no need () when paramater is null { std::cout << "second" << std::endl; }();// last add(), express will call this lamda func // 3 with return type auto kkk = []() { return 1; }()

代码简洁之二:函数只做一件事儿

函数应该做一件事.做好这件事.只做这一件事. 所以我们简化代码的一个简单方式就是不断拆分函数(Extract Method),一直拆分,拆分到不能再分出一个函数为止. 拆函数的过程就是一个概括目的.步骤,提取抽象层次动名词的过程.不要做只是解释代码的简单概括,要让函数中的语句处于一个相同抽象层次,如果是更细节的事儿,请再进一步拆分出一个函数出来.让代码拥有自顶向下的阅读顺序. 以我之前写的一个列表显示的action(MVC框架里面的某个控制器里面的一个方法),最开始代码是这样的: // 接收查询

代码简洁之四 统一抽象层次

我是一个phper,但是也写java,ruby,python,go等代码.最近一直focus on coding in clean,觉得抛开语言的门第之见,从思想上总结如何写更优雅代码的方式和方法,也希望阅读了本文的朋友留言讨论.当然我还是用php做代码演示,不过灵感是来自于<代码简洁之道>的java代码. 首先我要提出一个概念:写代码和写文章是完全一样的事情. 文章可以写得短小精悍,也可写得冗余拖沓.可以写得言简意干.调理清晰,也可被写成云里雾里的天书. 同样的现象也会发生在我们写得代码上.