C#中C ++的C ++相当于?

时间:2011-08-27 10:04:42

标签: c++

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 16777216;
}

有没有办法用模板技巧(或其他)在c ++中获得相同的语法?

11 个答案:

答案 0 :(得分:24)

看一下boost :: Coroutine。它做你想要的。 http://www.crystalclearsoftware.com/soc/coroutine/index.html#coroutine.intro

教程中的示例

http://www.crystalclearsoftware.com/soc/coroutine/coroutine/tutorial.html

int range_generator(generator_type::self& self, int min, int max) 
 {
   while(min < max)
     self.yield(min++);
   self.exit();
 }

答案 1 :(得分:8)

您可以随时手动编码。说实话,yield对我来说真的好像糖涂层(也是合作惯例)。

真正的协程是什么?有些州与:

捆绑在一起
  • 创建它的一个函数(不是构造函数吗?)
  • 一个移动到下一个状态的函数(传统上不是操作符++)?

在C ++中,它被称为InputIterator,可以任意胖。

所以,确实语法不会那么漂亮,但只需使用标准库就可以了:

static std::array<int, 6> const Array = {{1, 2, 4, 8, 16, 16777216}};

class Integers: public std::iterator<std::input_iterator_tag,
                                      int, ptrdiff_t, int const*, int>
{
public:
  Integers(): _index(0) {}

  operator bool() const { return _index < Array.size(); }

  Integers& operator++() { assert(*this); ++_index; return *this; }
  Integers operator++(int) { Integers tmp = *this; ++*this; return tmp; }

  int operator*() const { assert(*this); return Array[_index]; }
  int const* operator->() const { assert(*this); return &Array[_index]; }

private:
  size_t _index;
}; // class Integers

显然,由于确切地确定了什么状态存储,你决定是否所有状态都是预先计算的,或者是否部分(或整个部分)被懒惰地计算,并且可能被缓存,并且可能是多 - 螺纹,......你明白了这一点:)

答案 2 :(得分:8)

在C ++ 14中,您可以通过这种方式模仿yield

auto&& function = []() { 
    int i = 0; 
    return [=]() mutable { 
        int arr[] = {1,2,4,8,16,16777216}; 
        if ( i < 6 ) 
            return arr[i++]; 
        return 0; 
    }; 
}();

http://ideone.com/SQZ1qZ

提供了一个实时示例

答案 3 :(得分:2)

以下是ASM“滚动您自己的”版本:http://www.flipcode.com/archives/Yield_in_C.shtml

答案 4 :(得分:1)

尝试在c ++ coroutine

中实现yield

答案 5 :(得分:1)

如果您需要的只是类似于foreach的东西,那么C ++中提供了以下语法:

#define GENERATOR(name) \
struct name \
{ \
    template<typename F> \
    void operator()(F yield) \
/**/
#define _ };

template<typename Gen>
struct Adaptor
{
    Gen f;
    template<typename C>
    void operator*(C cont)
    {
        f(cont);
    }
};

template<typename Gen>
Adaptor<Gen> make_adaptor(Gen gen)
{
    return {gen};
}

#define FOREACH(arg, gen) make_adaptor(gen) * [&](arg)

#include <iostream>
using namespace std;

GENERATOR(integers)
{
    yield(1);
    yield(2);
    yield(4);
    yield(8);
    yield(16777216);
}_

int main()
{
    FOREACH(int i, integers())
    {
        cout << i << endl;
    };
}

Live Demo

如果您需要一点协程“权力”,那么您可以尝试stackless coroutines

或者,如果你需要充足的力量 - 那么请使用堆栈协程。有Boost.Coroutine库可以为不同的平台实现堆栈协程。

答案 6 :(得分:1)

为C ++ 17提出了类似的东西,并且在Visual C ++ 2015中已经有了一个实验性的实现。以下是来自Gor Nishanov的一个很好的概述talk,这是该提案的主要作者之一。

答案 7 :(得分:1)

Coroutines are in the C++20 draft并使用co_yield代替yield

另请参阅:What are coroutines in C++20?

第一个链接中有一些用法示例:(第二个可能是您要查找的内容)

  
      
  • 使用co_await运算符暂停执行直到恢复执行

    task<> tcp_echo_server() {
      char data[1024];
      for (;;) {
        size_t n = co_await socket.async_read_some(buffer(data));
        co_await async_write(socket, buffer(data, n));
      }
    }
    
  •   
  • 使用关键字co_yield暂停执行并返回值

    generator<int> iota(int n = 0) {
      while(true)
        co_yield n++;
    }
    
  •   
  • 使用关键字co_return完成返回值的执行

    lazy<int> f() {
      co_return 7;
    }
    
  •   

答案 8 :(得分:0)

当然,您可以随时编写自己的迭代器并根据需要从它们返回,但为什么要这样做?在给定的示例中,为什么不简单地将您的值放入像vector这样的容器中并迭代它?

答案 9 :(得分:0)

#include <setjmp.h>

class superclass
{
public:
    jmp_buf jbuf;
public:
    virtual int enumerate(void) { return -1; }
};

class subclass: public superclass
{
public:
    int enumerate()
    {
        static int i;
        static bool b = false;

        if(b) 
            longjmp(jbuf, 1);

        for(b = true, i = 0; i < 5; (i)++)
        {
            printf("\ndoing stuff: i = %d\n", i);

            if(setjmp(jbuf) != 1) 
                return i;    
        }
        return -1;
    }
};

使用代码......

int iret; 
subclass *sc;

sc = new subclass();
while((iret = sc->enumerate()) != -1)
{
    printf("\nsc->enumerate() returned: %d\n", iret);
}

刚刚开始工作;现在看起来很简单,虽然我有一些错误的开头:)

答案 10 :(得分:0)

如果您撰写static unsigned int checkpoint = 0;,请将所有变量设为staticswitch (checkpoint),将每个case: goto设置为某个标签,在每个return设置检查点上方设置为唯一value,并在下面定义label,并在函数集的末尾设置检查点为零,并将所有静态变量设置为其默认值,并在最后return为函数的结束值。如果您完成所有这些操作,则该功能将变为可枚举迭代。您在每个return行的上方和下方添加的两行使return命令的行为类似于yield returngoto允许您继续并从中断的地方恢复,static整数变量(如检查点)可帮助您记住停止的位置,继续/恢复的位置以及去向何处。您可以使用switch case语句测试它的值。制作所有其他变量static,就是将它们的值保存到下一个调用中,因此在下一次调用中,它们的值不会被重置!

例如:

#define PowerEnd INT_MIN
int Power(int number, int exponent)
{
    static unsigned int checkpoint = 0;
    static int result = 1, i = 0;
    switch (checkpoint)
    {
        case 1: goto _1;
    }
    for (i = 0; i < exponent; i++)
    {
        result *= number;
        checkpoint = 1;
        return result;
        _1:;
    }
    checkpoint = 0;
    result = 1;
    i = 0;
    return PowerEnd;
}
void main()
{
    while (true)
    {
        int result = Power(2, 8);
        if (result == PowerEnd)
            break;
        cout << result << endl;
    }
    //to print only the first 4 results (if there are at least 4 results) then
    for (int i = 0; i < 4; i++)
    {
        int result = Power(2, 8);
        if (result == PowerEnd)
            break;
        cout << result << endl;
    }
}

上述程序产生以下输出:

  

2     4     8     16     32     64     128     256     2     4     8     16