C++相当于 C# 产量

本文关键字:产量 相当于 C++ | 更新日期: 2023-09-27 18:06:53

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++ 中获得相同的语法?

C++相当于 C# 产量

看看 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();
}

您始终可以手动编写代码。说实话,对我来说,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

显然,由于确切地决定了存储什么状态,因此您可以决定是否所有状态都是预先计算的,或者部分(或全部(是延迟计算的,可能是缓存的,可能是多线程的,以及......你的想法:)

程自 C++20 年以来就在标准库中,并使用 co_yield 而不是 yield

另请参阅:C++20 中的协程是什么?

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

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

    task<> tcp_echo_server() {
       char data[1024];
       while (true) {
          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;
    }
    

在 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

这是ASM"滚动你自己的"版本: http://www.flipcode.com/archives/Yield_in_C.shtml

#include <stdio.h
#include <conio.h
#include <iostream.h

//
// marks a location in the program for resume
// does not return control, exits function from inside macro
//
// yield( x, ret )
//      x : the 'name' of the yield, cannot be ambiguous in the
//          function namespace
//    ret : the return value for when yield() exits the function;
//          must match function return type (leave blank for no return type)
#define yield(x,ret)                            '
    {                                           '
        /* store the resume location */         '
        __asm {                                 '
            mov _myStaticMkr,offset label_##x   '
        }                                       '
                                                '
        /* return the supplied value */         '
        return ret;                             '
    }                                           '
    /* our offset in the function */            '
    label_##x:

//
// resumes function from the stored offset, or
// continues without notice if there's not one
// stored
//
// resume()
//   <void
#define resume()                        '
    /* our stored offset */             '
    static _myStaticMkr=0;              '
                                        '
    /* test for no offset */            '
    if( _myStaticMkr )                  '
    {                                   '
        /* resume from offset */        '
        __asm                           '
        {                               '
            jmp _myStaticMkr            '
        }                               '
    }

// example demonstrating a function with an int return type
// using the yield() and resume() macros
//
// myFunc()
//   <void
int myFunc()
{
    resume();
    cout << "1'n";
    yield(1,1);
    cout << "2'n";
    yield(2,1);
    cout << "3'n";
    yield(3,1);
    cout << "4'n";
    return 0;
}

// main function
//
// main()
//   <void
void main( void )
{
    cout << "Yield in C++'n";
    cout << "Chris Pergrossi'n'n";
    myFunc();
    do
    {
        cout << "main()'n";
        cout.flush();
    } while( myFunc() );
    cout.flush();
    getch();
}

/*
// example demonstrating a function with no return type
// using the yield() and resume() macros
//
// myFunc()
//   <void
void myFunc()
{
    resume();
    cout << "1'n";
    yield(1);
    cout << "2'n";
    yield(2);
    cout << "3'n";
    yield(3);
    cout << "4'n";
    return;
}

// main function
//
// main()
//   <void
void main( void )
{
    cout << "Yield in C++'n";
    cout << "Chris Pergrossi'n'n";
    myFunc();
    for( int k = 0; k < 4; k ++ )
    {
        cout << "main()'n";
        cout.flush();
        myFunc();
    }
    cout.flush();
    getch();
}
*/  

如果你所需要的只是类似 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;
    };
}

现场演示

如果您需要一点协程"幂",那么您可以尝试无堆栈协程。

或者,如果您需要全功率 - 则可以使用堆叠协程。有 Boost.Coroutine 库,它为不同的平台实现了堆叠的协程。

尝试在 c++ 协程中实现 yield

如果你写static unsigned int checkpoint = 0;,让你所有的变量staticswitch (checkpoint),将每个case: goto设置为某个标签,在每个return上方将检查点设置为唯一值,在下面定义标签,在函数末尾将检查点设置为零,将所有静态变量设置为默认值,最后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;
    }
}

上述程序生成以下输出:

阿拉伯数字 4 8 16 32 64 128 256 2 4 8 16

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

#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);
}

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

当然,

您始终可以编写自己的迭代器,并从中返回任何您想要的内容,但是您为什么要这样做呢?在给定的示例中,为什么不简单地将您的值放入像 vector 这样的容器中并对其进行迭代呢?