Question

J'utilise le rendement dans plusieurs de mes programmes Python, et vraiment efface le code dans de nombreux cas. Je blog à ce sujet et il est l'une des pages les plus consultées de mon site.

C # aussi des offres rendement -. Il est mis en œuvre par le maintien de l'état du côté de l'appelant, fait par une classe générée automatiquement qui maintient l'état, les variables locales de la fonction, etc

Je suis en train de lire sur le C ++ 0x et ses compléments; et en lisant au sujet de la mise en œuvre de lambdas en C ++ 0x, je trouve que cela a été fait par les classes générées automatiquement aussi, équipé d'opérateur () stockant le code lambda. La question naturelle formée dans mon esprit: ils l'ont fait pour lambdas, pourquoi ne pas qu'ils le considèrent pour le soutien de « rendement », trop

Certes, ils peuvent voir la valeur des co-routines ... donc je ne peux que deviner qu'ils pensent implémentations macro-(tels que Simon Tatham de ) comme un substitut adéquat. Ils ne sont pas, cependant, pour de nombreuses raisons. État gardé-callee, non rentrante, à base de macro (qui seul est assez de raison), etc

Edit: yield ne dépend pas de la collecte des ordures, des fils ou des fibres. Vous pouvez lire l'article de Simon pour voir que je parle du compilateur faire une simple transformation, par exemple:

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

Dans:

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

Collecte des ordures ménagères? Discussions No.? Les fibres no? Non transformation simple? On peut dire que, oui.

Était-ce utile?

La solution

  

Ils l'ont fait pour lambdas, pourquoi ne pas qu'ils considèrent pour soutenir le rendement aussi?

Vérifier les documents . Quelqu'un at-il le proposer?

  

... Je ne peux deviner qu'ils considèrent implémentations macro-être un substitut adéquat.

Pas nécessairement. Je suis sûr qu'ils connaissent de telles solutions existent macro, mais les remplacer ne sont pas assez de motivation, lui-même, pour obtenir de nouvelles fonctions passées.


Même si il y a diverses questions autour d'un nouveau mot-clé, celles-ci pourraient être surmontés avec une nouvelle syntaxe, comme cela a été fait pour lambdas et en utilisant l'auto comme un type de retour de la fonction.

Radicalement nouvelles fonctionnalités ont besoin de puissants moteurs (à savoir personnes) pour une analyse complète et les caractéristiques de poussée par le comité, car ils auront toujours beaucoup de gens sceptiques d'un changement radical. Donc, même en l'absence de ce que vous verriez comme une raison technique forte contre une construction de rendement, il peut encore ne pas avoir été un soutien suffisant.

Mais fondamentalement, la bibliothèque standard C de a adopté un concept différent de itérateurs que vous verriez avec un rendement. Comparez aux itérateurs de Python, qui ne nécessitent deux opérations:

  1. an_iter.next () retourne l'élément suivant ou soulève StopIteration (à côté () builtin inclus dans 2,6 au lieu d'utiliser une méthode)
  2. iter (an_iter) retourne an_iter (vous pouvez traiter iterables et itérateurs identique dans les fonctions)

C ++ de 'les itérateurs sont utilisés par paires (qui doit être du même type), sont divisés en catégories, ce serait un glissement sémantique de transition en quelque chose de plus favorable à une construction élastique, et ce changement ne cadrent bien avec les concepts (qui a depuis été abandonné, mais qui est venu relativement tard). Par exemple, voir le justification pour (à juste titre, si malheureusement) rejeter mon commentaire sur le changement de base gamme pour les boucles à une forme qui ferait écrire cette autre forme de iterator beaucoup plus facile.

Pour préciser concrètement ce que je veux dire sur les différentes formes de iterator: vos besoins générés par exemple de code autre type à type iterator ainsi que les équipements associés, pour obtenir et maintenir ces itérateurs. Non qu'il ne pouvait pas être traitée, mais ce n'est pas aussi simple que vous pouvez tout d'abord imaginer. La complexité réelle est la « simple transformation » respect des exceptions pour les variables « locales » (y compris pendant la construction), le contrôle de durée de vie des variables « locales » dans les étendues locales dans le générateur (plus aurait besoin d'être sauvé à travers des appels), et ainsi de suite.

Autres conseils

Je ne peux pas dire pourquoi ils ne sont pas ajouter quelque chose comme ça, mais dans le cas de lambdas, ils n'étaient pas juste ajouté à la langue non plus.

Ils ont commencé la vie comme une mise en œuvre bibliothèque Boost, ce qui prouve que

  • lambdas sont largement utiles: beaucoup de gens vont les utiliser quand ils sont disponibles, et que
  • une implémentation bibliothèque en C ++ 03 souffre d'un certain nombre de lacunes.

Sur cette base, le comité a décidé d'adopter une sorte de lambdas en C ++ 0x, et je crois qu'ils d'abord l'expérience en ajoutant des termes plus généraux caractéristiques pour permettre une mieux la mise en œuvre de la bibliothèque Boost a.

Et finalement, ils ont fait une caractéristique de langage de base, parce qu'ils avaient pas d'autre choix. Car il n'a pas été possible de faire une assez bon mise en œuvre bibliothèque

Les nouvelles fonctionnalités du langage de base ne sont pas simplement ajouté à la langue, car ils semblent être une bonne idée. Le comité est très réticents à les ajouter et la fonctionnalité en question vraiment doit se prouver. Il faut montrer que la fonction est:

  • de mettre en œuvre dans le compilateur,
  • va résoudre un besoin réel et
  • qu'une mise en œuvre bibliothèque ne serait pas assez bon.

Dans le cas si un mot-clé yield, nous savons que le premier point peut être résolu. Comme vous l'avez montré, il est une transformation assez simple qui peut être fait mécaniquement.

Le second point est délicate. Combien d'un besoin pour c'est là ? Comment largement utilisés sont les implémentations bibliothèque qui existent? Combien de personnes ont demandé pour cela, ou les propositions soumises pour elle?

Le dernier point semble passer trop. Au moins en C ++ 03, une implémentation bibliothèque souffre quelques défauts, comme vous l'avez dit, qui pourrait justifier une mise en œuvre du langage de base. Une meilleure mise en œuvre pourrait être faite dans la bibliothèque C ++ 0x bien?

Alors je suppose que le principal problème est vraiment un manque d'intérêt. C ++ est déjà une énorme langue, et personne ne veut grandir il plus à moins que les caractéristiques sont ajoutés vraiment vaut. Je soupçonne que ce n'est pas assez utile.

Ajout d'un mot-clé est toujours délicat, car il invalident code précédemment valide. Vous essayez d'éviter que dans une langue avec une base de code aussi grand que C ++.

L'évolution du C ++ est un processus public. Si vous vous sentez yield devrait être là, formuler une demande appropriée au comité C ++ standard.

Vous obtiendrez votre réponse, directement à partir des personnes qui ont pris la décision.

Alors, on dirait qu'il n'a pas fait dans C ++ 11, ou C ++ 14, mais peut-être en voie de C ++ 17. Jetez un oeil à la conférence C ++ Coroutines, une abstraction négative en tête de CppCon2015 et le papier ici .

Pour résumer, ils travaillent à étendre c ++ fonctions pour avoir le rendement et attendre que les caractéristiques des fonctions. On dirait qu'ils ont une mise en œuvre initiale dans Visual Studio 2015, pas sûr si clang a une encore mise en œuvre. En outre, il semble que leur peut y avoir des problèmes avec l'utilisation de rendement et les mots-clés comme await.

La présentation est intéressante parce qu'il parle de combien il code réseau simplifié, où vous attendez pour les données à venir pour poursuivre la séquence de traitement. Étonnamment, il semble que l'utilisation de ces nouveaux résultats de coroutines en plus vite / moins de code que ce que l'on ferait aujourd'hui. Il est une excellente présentation.

La proposition de fonctions réactivables pour C ++ se trouve .

En général, vous pouvez suivre ce qui se passe par les journaux du comité , bien qu'il vaut mieux pour garder une trace plutôt que de chercher un problème spécifique.

Une chose à retenir sur le C ++ comité est qu'il est un comité de bénévoles, et ne peut accomplir tout ce qu'il veut. Par exemple, il n'y avait pas de type carte de hachage dans la norme d'origine, parce qu'ils ne pouvaient pas réussi à le faire dans le temps. Il pourrait être qu'il n'y avait personne au sein du comité qui se souciait assez sur yield et ce qu'il fait pour vous assurer que le travail se est fait.

La meilleure façon de savoir serait de demander à un membre du comité actif.

Eh bien, pour un tel exemple trivial que cela, le seul problème que je vois est que std::type_info::hash_code() n'est pas spécifié constexpr. Je crois qu'une mise en œuvre conforme peut encore faire en sorte et l'appui. Quoi qu'il en soit le vrai problème est d'obtenir des identifiants uniques, donc il pourrait y avoir une autre solution. (Il est évident que j'ai emprunté votre construction « commutateur maître », merci.)

#define YIELD(X) do { \
    constexpr size_t local_state = typeid([](){}).hash_code(); \
    return (X); state = local_state; case local_state: ; } \
while (0)

Utilisation:

struct GeneratedFibonacci {
    size_t state;
    int a, b;

    GeneratedFibonacci() : state (0), a (0), b (1) {}

    int operator()() {
        switch (state) {
        case 0:
            while (true) {
                YIELD( a );
                int c = a + b;
                a = b;
                b = c;
            }
        }
    }
}

Hmm, ils doivent également garantir que le hachage est pas 0. Pas trop grave non plus. Et une macro DONE est facile à mettre en œuvre.


Le vrai problème est ce qui se passe lorsque vous revenez d'un champ avec des objets locaux. Il n'y a pas d'espoir de sauver un cadre hors de la pile dans un langage basé sur C. La solution consiste à utiliser une véritable coroutine et C ++ 0x fait directement avec l'adresse que fils et futures.

Considérez ce générateur / coroutine:

void ReadWords() {
    ifstream f( "input.txt" );

    while ( f ) {
        string s;
        f >> s;
        yield s;
    }
}

Si un truc similaire est utilisé pour yield, f est détruite au premier yield, et il est illégal de continuer la boucle après, parce que vous ne pouvez pas goto ou switch passé une définition d'objet non-POD.

il y a eu plusieurs de mise en œuvre coroutines les bibliothèques de l'espace utilisateur. Cependant, et voici l'accord, ces mises en œuvre reposent sur des détails non standard. Par exemple, nulle part sur le standard C ++ est spécifié comment les cadres de pile sont conservés. La plupart des implémentations simplement copier la pile car c'est ainsi la plus c ++ travail implémentations

en ce qui concerne les normes, c ++ aurait contribué à soutenir coroutine en améliorant la spécification des cadres de pile.

En fait, « ajouter » à la langue ne semble pas une bonne idée pour moi, parce que cela vous en tenir à une mise en œuvre de « assez bon » pour la plupart des cas qui est entièrement compilateur dépendant. Pour les cas où l'utilisation d'une matière coroutine, ce n'est pas acceptable de toute façon

d'accord avec @Potatoswatter premier.

Pour soutenir coroutine est pas la même chose que le soutien pour les lambdas et non que simple transformation comme joué avec l'appareil de Duff.

Vous avez besoin coroutines pleine asymétrique (stackful ) à travailler comme des générateurs en Python. La mise en œuvre de Simon Tatham et Chris' sont tous les deux stackless alors que Boost.Coroutine est un de stackfull si elle est lourd.

Malheureusement, C ++ 11 encore ne pas yield pour coroutines encore, peut-être C ++ 1y;)

PS: Si vous aimez vraiment générateurs de style Python, consultez la page cette .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top