GithubHelp home page GithubHelp logo

[译]C++20: 协程一瞥 about blog HOT 4 OPEN

guodongxiaren avatar guodongxiaren commented on June 3, 2024
[译]C++20: 协程一瞥

from blog.

Comments (4)

guodongxiaren avatar guodongxiaren commented on June 3, 2024

函数的进化之路

下面的代码样例一步一步地展示着函数的进化之路:

// functionEvolution.cpp

int func1() {
    return 1972;
}

int func2(int arg) {
    return arg;
}

double func2(double arg) {
    return arg;
}

template <typename T>
T func3(T arg) {
    return arg;
}

struct FuncObject4 {
    int operator()() { // (1)
        return 1998;
    }
};

auto func5 = [] {
    return 2011;
};

auto func6 = [] (auto arg){
    return arg;
};

int main() {

    func1();        // 1972

    func2(1998);    // 1998
    func2(1998.0);  // 1998.0
    func3(1998);    // 1998
    func3(1998.0);  // 1998.0
    FuncObject4 func4;
    func4();        // 1998

    func5();        // 2011

    func6(2014);    // 2014
    func6(2014.0);  // 2014

}   
  • 伴随着1972年,C语言标准的诞生,我们有了普通函数:fun1。
  • 1998年C++的标准使得函数变得更加强大。我们拥有了:
    • 函数重载:fun2。
    • 函数模板:fun3。
    • 函数对象:fun4。之前,它被错误的称为仿函数(functors)由于它是operator()重载的产物。
  • C++11给了我们lamda函数:fun5。
  • C++14,lambda函数拥有了泛型。

让我们迈向未来,看看特殊的协程:生成器。

from blog.

guodongxiaren avatar guodongxiaren commented on June 3, 2024

生成器

在传统C++中,我们可以实现一个贪婪的生成器(greedy generator)。

贪婪生成器

下面的代码简单有效。函数getNumbers返回从begin到end的累加整数。begin小于end并且inc是正数。

// greedyGenerator.cpp

#include <iostream>
#include <vector>

std::vector<int> getNumbers(int begin, int end, int inc = 1) {
  
    std::vector<int> numbers;                      // (1)
    for (int i = begin; i < end; i += inc) {
        numbers.push_back(i);
    }
  
    return numbers;
  
}

int main() {

    std::cout << std::endl;

    const auto numbers= getNumbers(-10, 11);
  
    for (auto n: numbers) std::cout << n << " ";
  
    std::cout << "\n\n";

    for (auto n: getNumbers(0, 101, 5)) std::cout << n << " ";

    std::cout << "\n\n";

}

程序的输出符合预期:
image

当然,我也可以用算法std::iota重新造轮子,这样实现的getNumbers会更好。按下不表。

程序中两次输出是很有必要的。第一行的vector numbers可以得到所有值,尽管我只对这个拥有1000个元素的vector的前5个元素感兴趣。另外将这个函数转型成懒惰生成器十分简单。

懒惰生成器

就这样:

// lazyGenerator.cpp

#include <iostream>
#include <vector>

generator<int> generatorForNumbers(int begin, int inc = 1) {
  
  for (int i = begin;; i += inc) {
    co_yield i;
  }
  
}

int main() {

    std::cout << std::endl;

    const auto numbers= generatorForNumbers(-10);                   // (2)
  
    for (int i= 1; i <= 20; ++i) std::cout << numbers << " ";       // (4)
  
    std::cout << "\n\n";
                                                         
    for (auto n: generatorForNumbers(0, 5)) std::cout << n << " ";  // (3)

    std::cout << "\n\n";

}

greedyGenerator.cpp的函数getNumbers返回了一个vector。lazyGenerator.cpp中的generatorForNumbers返回了一个生成器。
(2)处的numbers 或者(3)处的 generatorForNumbers(0, 5) 在请求时返回一个新数字。基于范围的循环触发了这一查询请求。说的再清晰一点。协程通过co_yield返回值i 并且理解挂断了运行。如果一个新的值被请求,这个协程将继续执行。

(3)处的表达式generatorForNumbers(0, 5) 仅仅是生成器的原地(in-place)用法。我想明确这一点,因为for循环没有终止条件,generatorForNumbers创造了一个无穷无尽的数据流。如果我仅仅想请求有限个数的值(像(4)处那样),那么无限的数据流没什么问题。而(3)处这种写法,表达式将永远运行下去!

from blog.

guodongxiaren avatar guodongxiaren commented on June 3, 2024

接下来是什么?

我们并没有在C++20中获得完整的协程。但是我们得到了一个可以自己实现协程的框架,你可以假设对于这个话题,我将会有很多内容可以写。


以上为译文

THE END


from blog.

guodongxiaren avatar guodongxiaren commented on June 3, 2024

译者注

std::iota生成器:

#include <iostream>
#include <numeric>
#include <vector>
void iota_test() {
    std::vector<int> foo(10);
    // 将从 0 开始的 10 次递增值赋值给 foo
    std::iota(foo.begin(), foo.end(), 0);
    // 输出 foo 中的内容
    std::copy(foo.begin(),foo.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
}
int main() {
    iota_test();
}

输出:

0 1 2 3 4 5 6 7 8 9

iota在头文件numeric中。并且这个不是C++11的,之前就有。

from blog.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.