为什么不把yield添加到C ++ 0x? [英] Why wasn't yield added to C++0x?

查看:231
本文介绍了为什么不把yield添加到C ++ 0x?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在许多Python程式中一直使用yield,并且在许多情况下 清除代码。我对其进行了博客,这是我网站上的热门网页之一。



C#还提供yield - 它通过调用者端的状态保持实现,通过自动生成的类保持状态,函数的局部变量等。



我目前正在阅读关于C ++ 0x及其添加;并且在阅读关于在C ++ 0x中实现lambdas的时候,我发现它是通过自动生成的类来完成的,配备了存储lambda代码的operator()。在我心中形成的自然的问题:他们为兰布达做了这件事,为什么他们不支持收益?



当然,他们可以看到协作例程的价值...所以我只能猜测他们认为基于宏的实现(例如西塔姆Tatham的)作为适当的替代品。然而,它们不是因为许多原因:被调用的状态,不可重入的,基于宏的(仅这个原因足够)等。



编辑: yield 不依赖于垃圾收集,线程或光纤。你可以阅读Simon的文章,看看我在说的编译器做一个简单的转换,如:

  int fibonacci {
int a = 0,b = 1;
while(true){
yield a;
int c = a + b;
a = b;
b = c;
}
}

进入:

  struct GeneratedFibonacci {
int state;
int a,b;

生成的Fibonacci():state(0),a(0),b(1){}

int operator ){
case 0:
state = 1;
while(true){
return a;

case 1:
int c = a + b;
a = b;
b = c;
}
}
}
}

垃圾采集?不是线程?不是。不是。简单的变换?可以说,是的。

解决方案


他们为lambdas做了,为什么他们不认为


检查论文。有人提出吗?


...我只能猜测他们认为基于宏的实现是一个足够的替代。 >

不一定。我相信他们知道这样的宏解决方案存在,但替换它们是不够的动机,自己,以获得新的功能通过。






即使新关键字存在各种问题,也可以使用新的语法来克服这些问题,例如对于lambdas和使用auto作为函数返回类型。



根本的新功能需要强大的驱动力(即人们)通过委员会完全分析和推动功能,因为他们总是会有很多人怀疑激进的变化。因此,即使没有你认为作为一个强大的技术原因反对收益结构,可能仍然没有足够的支持。



但从根本上说,C ++标准库已经接受一个不同的迭代器概念,比你看到的yield。与Python的迭代器相比,它只需要两个操作:


  1. an_iter.next()返回下一个项目或者提高StopIteration




  2. C ++的迭代器是成对使用的(它们必须是相同的类型),被分成类别,它将是一个语义转换,转换成更适合yield结构的东西,移位不适合与概念(这已经被放弃,但是相对较晚)。例如,请参阅基本原理(有理由,如果令人失望地)拒绝我的改变基于范围的for循环的形式,这将使写这种不同形式的迭代器更容易。



    具体阐明我的意思不同的迭代器形式:生成的代码示例需要另一个类型作为迭代器类型以及用于获取和维护这些迭代器的相关机制。不是它不能被处理,但它不是你想象的那么简单。真正的复杂性是简单变换,其遵守局部变量(包括在构建期间)的异常,控制生成器内的局部范围中局部变量的生存期(大多数需要在调用中保存)。


    I have been using yield in many of my Python programs, and it really clears up the code in many cases. I blogged about it and it is one of my site's popular pages.

    C# also offers yield – it is implemented via state-keeping in the caller side, done through an automatically generated class that keeps the state, local variables of the function, etc.

    I am currently reading about C++0x and its additions; and while reading about the implementation of lambdas in C++0x, I find out that it was done via automatically generated classes too, equipped with operator() storing the lambda code. The natural question formed in my mind: they did it for lambdas, why didn't they consider it for support of "yield", too?

    Surely they can see the value of co-routines... so I can only guess that they think macro-based implementations (such as Simon Tatham's) as an adequate substitute. They are not, however, for many reasons: callee-kept state, non-reentrant, macro-based (that alone is reason enough), etc.

    Edit: yield doesn't depend on garbage collection, threads, or fibers. You can read Simon's article to see that I am talking about the compiler doing a simple transformation, such as:

    int fibonacci() {
        int a = 0, b = 1;
        while (true) {
            yield a;
            int c = a + b;
            a = b;
            b = c;
        }
    }
    

    Into:

    struct GeneratedFibonacci {
        int state;
        int a, b;
    
        GeneratedFibonacci() : state (0), a (0), b (1) {}
    
        int operator()() {
            switch (state) {
            case 0:
                state = 1;
                while (true) {
                    return a;
    
            case 1:
                    int c = a + b;
                    a = b;
                    b = c;
                }
            }
        }
    }
    

    Garbage collection? No. Threads? No. Fibers? No. Simple transformation? Arguably, yes.

    解决方案

    They did it for lambdas, why didn't they consider it for supporting yield, too?

    Check the papers. Did anyone propose it?

    ...I can only guess that they consider macro-based implementations to be an adequate substitute.

    Not necessarily. I'm sure they know such macro solutions exist, but replacing them isn't enough motivation, on its own, to get new features passed.


    Even though there are various issues around a new keyword, those could be overcome with new syntax, such as was done for lambdas and using auto as a function return type.

    Radically new features need strong drivers (i.e. people) to fully analyze and push features through the committee, as they will always have plenty of people skeptical of a radical change. So even absent what you would view as a strong technical reason against a yield construct, there may still not have been enough support.

    But fundamentally, the C++ standard library has embraced a different concept of iterators than you'd see with yield. Compare to Python's iterators, which only require two operations:

    1. an_iter.next() returns the next item or raises StopIteration (next() builtin included in 2.6 instead of using a method)
    2. iter(an_iter) returns an_iter (so you can treat iterables and iterators identically in functions)

    C++'s iterators are used in pairs (which must be the same type), are divided into categories, it would be a semantic shift to transition into something more amenable to a yield construct, and that shift wouldn't fit well with concepts (which has since been dropped, but that came relatively late). For example, see the rationale for (justifiably, if disappointingly) rejecting my comment on changing range-based for loops to a form that would make writing this different form of iterator much easier.

    To concretely clarify what I mean about different iterator forms: your generated code example needs another type to be the iterator type plus associated machinery for getting and maintaining those iterators. Not that it couldn't be handled, but it's not as simple as you may at first imagine. The real complexity is the "simple transformation" respecting exceptions for "local" variables (including during construction), controlling lifetime of "local" variables in local scopes within the generator (most would need to be saved across calls), and so forth.

    这篇关于为什么不把yield添加到C ++ 0x?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆