在 C# 中等效于 C++ 的 Yield?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7213839/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:37:01  来源:igfitidea点击:

Equivalent in C++ of Yield in C#?

c++

提问by Guillaume07

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

Is there a way with template trick (or other) to get the same syntax in c++?

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

采纳答案by ?ukasz Milewski

Take a look at boost::Coroutine. It does what you want. http://www.crystalclearsoftware.com/soc/coroutine/index.html#coroutine.intro

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

Example from tutorial

教程中的示例

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

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

回答by Matthieu M.

You can always code this by hand. Truthfully, yieldreally seems like sugar coating to me (and co-routines too).

您始终可以手动编写代码。说实话,yield对我来说真的像是糖衣(还有协同程序)。

What a coroutine is, really ? Some state bundled up together with:

什么是协程,真的吗?一些状态捆绑在一起:

  • one function to create it (isn't it a constructor ?)
  • one function to move to the next state (isn't it operator++, traditionally ?)
  • 一个函数来创建它(它不是一个构造函数吗?)
  • 移动到下一个状态的一个函数(传统上不是 operator++ 吗?)

In C++, it's called an InputIterator, and can be arbitrarily fat.

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

So, it's true that the syntax won't be as pretty, but this should do, just with the Standard Library:

因此,确实语法不会那么漂亮,但这应该可以,只需使用标准库:

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

And obviously, since youdecide exactly what state is stored, you decide if all is pre-computed or if part (or whole of it) is lazily computed, and possibly cached, and possibly multi-threaded, and ... you got the idea :)

显然,由于确切地决定存储什么状态,您决定是否所有都是预先计算的,或者是否部分(或全部)是延迟计算的,可能是缓存的,也可能是多线程的,并且......你得到了主意 :)

回答by Feng Wang

In C++14, you can mimic yieldthis way:

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

A live example is available at http://ideone.com/SQZ1qZ

http://ideone.com/SQZ1qZ提供了一个现场示例

回答by Bernhard Barker

Coroutines are in the C++20 draftand uses co_yieldinstead of yield.

协程都在C ++ 20草案和用途co_yield代替yield

See also: What are coroutines in C++20?

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

There are some example usages in the first link: (the second one is probably what you're looking for)

第一个链接中有一些示例用法:(第二个可能是您正在寻找的)

  • uses the co_awaitoperator to suspend execution until resumed

    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));
      }
    }
    
  • uses the keyword co_yieldto suspend execution returning a value

    generator<int> iota(int n = 0) {
      while(true)
        co_yield n++;
    }
    
  • uses the keyword co_returnto complete execution returning a value

    lazy<int> f() {
      co_return 7;
    }
    
  • 使用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;
    }
    

回答by Michael IV

Here is ASM "roll your own" version : http://www.flipcode.com/archives/Yield_in_C.shtml

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

*/  

回答by Evgeny Panasyuk

If all what you need is just foreach-like stuff, then following syntax is available in C++:

如果您需要的只是类似 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

现场演示

If you need a little bit of coroutine "power", then you can try stackless coroutines.

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

Or if you need full power - then go with stackful coroutines. There is Boost.Coroutinelibrary which implements stackful coroutines for different platforms.

或者,如果您需要全部功能 - 那就使用堆栈式协程。有Boost.Coroutine库,它为不同的平台实现了堆栈式协程。

回答by Guillaume07

An try to implement yield in c++ coroutine

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

回答by mattnewport

Something similar is proposed for C++17 and there is already an experimental implementation in Visual C++ 2015. Here's a good overview talkfrom Gor Nishanov, one of the main authors of the proposal.

类似的事情提出了C ++ 17,且已存在在Visual C ++的实验实现2015年这里有一个很好的概述谈话从Gor的Nishanov,该建议的主要作者之一。

回答by TeaWolf

You can of course always write your own iterators and return from them whatever you desire, but why would you want to? In the given example, why not simply put your values into a container like vector and iterate over that?

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

回答by Ian

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

To use the code...

要使用代码...

int iret; 
subclass *sc;

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

Just got this working; it seems quite simple now, although I had a few false starts with it :)

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