添加【金融之家】为好友

扫描二维码

或添加QQ 【724996599】成为为好友

满足以下场景,获得更高通过率:

1. 新融资求报道

2. 新公司求报道

3. 新产品求报道

4. 金融新闻爆料

我知道了

如有投稿需求,请发邮件至 tougao@jrzj.com

会有专人和您联系

我知道了

EOS开发的c++指南——迭代器和Lambda表达式

来源: 首页 > 新三板

2018-09-28 17:50:42 

让我们来讨论迭代器,这是一个非常有用的工具,在整个EOS代码库中都被大量使用。如果您处于JavaScript的背景下,您可能已经熟悉迭代器,就像循环中使用的迭代器一样。迭代器的关键概念是提供一种更好的遍历项集合的方法。额外的好处是,您可以为任何定制类实现迭代器接口,使迭代器成为遍历数据的通用方法。


// @url: https://repl.it/@MrToph/CPPBasics-Iterators
#include <iostream>
#include <vector>
using namespace std;
int main()
{
  vector<int> v{2, 3, 5, 8};
  // old way to iterate
  for (int i = 0; i < v.size(); i++)
  {
    cout << v[i] << "\n";
  }
  // using Iterators
  // begin() returns an iterator that points to the beginning of the vector
  // end() points to the end, can be compared using != operator
  // iterators are incremented by using the + operator thanks to operator-overloading
  for (vector<int>::iterator i = v.begin(); i != v.end(); i++)
  {
    // iterators are dereferenced by * like pointers
    // returns the element the iterator is currently pointing to
    cout << *i << "\n";
  }
  // auto keyword allows you to not write the type yourself
  // instead C++ infers it from the return type of v.begin
  for (auto i = v.begin(); i != v.end(); i++)
  {
    cout << *i << "\n";
  }
  // can use arithmetic to "jump" to certain elements
  int thirdElement = *(v.begin() + 2);
  cout << "Third: " << thirdElement << "\n";
  // end is the iterator that points to the "past-the-end" element
  // The past-the-end element is the theoretical element that would follow the last element in the vector.
  // It does not point to any element, and thus shall not be dereferenced.
  int lastElement = *(v.end() - 1);
  cout << "Last: " << lastElement << "\n";
  // do not go out of bounds by iterating past the end() iterator
  // the behavior is undefined
  // BAD: v.end() + 1, v.begin() + 10
}


在现代c++中,迭代器是迭代元素集合(向量、列表、映射)的首选方法。另外,可以避免键入冗长的类型,但可能会导致缺乏表现力的代码。


Lambda表达式


有了迭代器,我们可以开始研究现代c++的函数式编程概念。标准库中的许多函数都将由两个迭代器(开始和结束)和一个匿名函数(lambda函数)表示的元素范围作为参数。然后将这个匿名函数应用于范围内的每个元素。它们之所以被称为匿名函数,是因为它们不绑定到变量,而是绑定于短逻辑块中,作为内联参数传递给高阶函数。通常,它们对于传递给它们的函数是唯一的,因此不需要拥有名称。
有了它,我们可以实现类似于排序、映射、过滤等结构,这些结构在JavaScript等语言中很容易实现:


[1,2,3,4].map(x => x*x).filter(x => x % 2 === 1).sort((a,b) => b - a)


c++中的代码并不简洁,但是结构是一样的。STD库中的许多函数式编程助手都是在半开区间上操作的,这意味着包含了较低的区间,而排除了较高的区间。


// @url: https://repl.it/@MrToph/CPPBasics-Lambdas
#include <iostream>
#include <vector>
// for sort, map, etc.
#include <algorithm>
using namespace std;
int main()
{
  vector<int> v{2, 1, 4, 3, 6, 5};
  // first two arguments are the range
  // v.begin() is included up until v.end() (excluded)
  // sorts ascending
  sort(v.begin(), v.end());
  // in C++, functions like sort mutate the container (in contrast to immutability and returning new arrays in other languages)
  for (auto i = v.begin(); i != v.end(); i++)
  {
    cout << *i << "\n";
  }
  // sort it again in descending order
  // third argument is a lambda function which is used as the comparison for the sort
  sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
  // functional for_each, can also use auto for type
  for_each(v.begin(), v.end(), [](int a) { cout << a << "\n"; });
  vector<string> names{"Alice", "Bob", "Eve"};
  vector<string> greetings(names.size());
  // transform is like a map in JavaScript
  // it applies a function to each element of a container
  // and writes the result to (possibly the same) container
  // first two arguments are range to iterate over
  // third argument is the beginning of where to write to
  transform(names.begin(), names.end(), greetings.begin(), [](const string &name) {
    return "Hello " + name + "\n";
  });
  // filter greetings by length of greeting
  auto new_end = std::remove_if(greetings.begin(), greetings.end(), [](const string &g) {
    return g.size() > 10;
  });
  // iterate up to the new filtered length
  for_each(greetings.begin(), new_end, [](const string &g) { cout << g; });
  // alternatively, really erase the filtered out elements from vector
  // so greetings.end() is the same as new_end
  // greetings.erase(new_end, greetings.end());
  // let's find Bob
  string search_name = "Bob";
  // we can use the search_name variable defined outside of the lambda scope
  // notice the [&] instead of [] which means that we want to do "variable capturing"
  // i.e. make all local variables available to use in the lambda function
  auto bob = find_if(names.begin(), names.end(), [&](const string &name) {
    return name == search_name;
  });
  // find_if returns an iterator referncing the found object or the past-the-end iterator if nothing was found
  if (bob != names.end())
    cout << "Found name " << *bob << "\n";
}


在c++中,匿名函数的语法是一种习惯性的。它们由括号指定,后面跟着一个参数列表,如[](int a, int b) -> bool{返回a > b;}。注意-> bool指定一个返回值。通常情况下,您可以避免表示返回类型,因为它可以从函数体中的返回类型推断出来。


如果您想使用lambda函数之外的作用域中定义的变量,您需要进行变量捕获。再次有可能通过引用或值将参数传递给函数。


·要通过引用传递,您需要用&字符开始lambda(就像在函数中使用引用时一样):[&]
·要传递值,使用=字符:[=]


还可以通过值和引用进行混合匹配捕获。

例如,[=,&foo]将为所有变量创建副本,除了通过引用捕获的foo。

它有助于理解使用lambdas在幕后发生的事情:


实际上,lambdas的实现方法是创建一个小类;这个类重载运算符(),因此它的行为就像一个函数。lambda函数是该类的一个实例;在构造类时,周围环境中的任何变量都被传递到lambda函数类的构造函数中,并作为成员变量进行保存。实际上,这和函数子集的概念很像。c++ 11的好处是,这样做几乎变得很容易——所以您可以一直使用它,而不是只在非常罕见的情况下编写一个全新的类才有意义。   CProgramming Lambda函数


Lambda函数在EOS智能合约中被大量使用,因为它们提供了一种在短时间内修改数据的非常方便的方式。标准库中有更多函数的工作方式与我们已经看到的sort、transform、remove_if和find_if类似。它们都通过<algorithm>报头导出。

免责声明:[ 金融之家-JRZJ.COM刊发此文目的在于传递更多信息,文章内容仅供参考,不构成投资建议。投资者据此操作,风险自担 ]

责任编辑: