一段 c++ 实现 generator 的有趣代码

Coroutines and C++20 这篇文章时发现一段有意思的代码,用 C++ 模拟 python 中的 range 函数。核心是使用函数静态变量,但有些细节很有意思,记录一下。

第一段代码:

// A bad simulation of coroutine, no state saving
#include<iostream>
int range(int a, int b) 
{ 
  static long long int i = a-1;
  for (;i < b;) 
  {  
   return ++i; 
  } 
  return 0; 
}
int main() 
{ 
 int i;
 for (; i=range(1, 5);) 
   std::cout << i << '\n';
 return 0; 
}

这里有几个细节:

  • static 变量用来在多次调用中保存历史信息。
  • main 函数中 for 循环除了实现打印多个值外,还利用 for 循环的判断机制,避免了打印完 4 后再打印一个 0。

这个函数也有缺点,因为 static 定义变量那一行只会执行一次,所以这个 range 函数重复调用是不符合预期的。所以作者又写了升级版:

// A better simulation of coroutine, state saving!!
#include<iostream>
int range(int a, int b) 
{ 
  static long long int i;
  static int state = 0;
  switch (state)
  {
    case 0: /* start of function */
        state = 1;
        for (i = a; i < b; i++)
        {
         return i; /* Returns control */
    case 1:; /* resume control straight after the return */
        }
  }
  state = 0;
  return 0;
}
int main() 
{ 
 int i;
for (; i=range(1, 5);) 
   std::cout << i << '\n';
 return 0; 
}

这段代码除了上一段代码的核心细节点外,还增加了:

  • static 变量 i 只有在 state==0 时才会赋值,因此 range 可以多次调用(但不可并发调用)。
  • range 内的 for 循环体包括了case 1这一行,因此在范围内时每次 return 都是由return i返回的。(for 循环体是能和 case 混合的!amazing!)

总结

利用 static 变量保存历史信息,for + switch 语句巧妙组合实现状态重置,for 语句中条件判断避免输出无用信息。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容