Est-il un standard C++ équivalent de IEnumerable<T> en C#?
Ou est-il sécuritaire d'utiliser le vecteur si l'agent Recenseur de T est juste de lister tous les éléments?
- Il y a un Équivalent vous pourriez utiliser en C++ pourriez-vous voir un exemple de code
- Merci! J'essaie juste de voir si il y a des approches plus appropriées autres que l'aide de vecteur, qui pourrait permettre à nos propres implémentations de GetEnumerator() en C++.
Vous devez vous connecter pour publier un commentaire.
Il n'est pas nécessaire en C++, et voici pourquoi:
C# ne supporte dynamique polymorphisme. Afin de créer une réutilisables algorithme, vous avez besoin d'une interface qui tous les itérateurs allons mettre en œuvre. C'est
IEnumerator<T>
, etIEnumerable<T>
est une usine pour le retour d'un itérateur.Modèles C++, d'autre part, le soutien duck-typing. Cela signifie que vous n'avez pas besoin de contraindre un paramètre de type générique par une interface afin d'accéder aux membres -- le compilateur va rechercher des membres par nom pour chaque instanciation du modèle.
C++ conteneurs et les itérateurs ont implicite des interfaces, qui est l'équivalent .NET
IEnumerable<T>
,IEnumerator<T>
,ICollection<T>
,IList<T>
, à savoir:Pour les conteneurs:
iterator
etconst_iterator
typedefsbegin()
fonction membre -- remplit le besoin pourIEnumerable<T>::GetEnumerator()
end()
fonction membre -- au lieu deIEnumerator<T>::MoveNext()
valeur de retourPour les itérateurs:
value_type
typedefoperator++
-- au lieu deIEnumerator<T>::MoveNext()
operator*
etoperator->
-- au lieu deIEnumerator<T>::Current
operator*
-- au lieu deIList<T>
indexeur setteroperator==
etoperator!=
-- pas de véritable équivalent dans .NET, mais avec du conteneurend()
correspondIEnumerator<T>::MoveNext()
valeur de retourPour un accès aléatoire itérateurs:
operator+
,operator-
,operator[]
-- au lieu deIList<T>
Si vous définissez ces, puis des algorithmes standard fonctionnera avec votre conteneur et de l'itérateur. Pas d'interface, pas de fonctions virtuelles sont nécessaires. Pas à l'aide de fonctions virtuelles fait C++ générique code plus vite que son équivalent .NET code, parfois beaucoup plus rapide.
Remarque: lors de l'écriture des algorithmes génériques, il est préférable d'utiliser
std::begin(container)
etstd::end(container)
plutôt que sur le contenant des fonctions membres. Qui permet à votre algorithme pour être utilisé avec des tableaux (qui n'ont pas de fonctions membres) outre les conteneurs STL. Raw tableaux et de matières pointeurs de satisfaire à toutes les autres exigences de conteneurs et d'itérateurs, avec cette seule exception à la règle.IEnumerator
montre l'ignorance de ce quiIEnumerator
est en réalité. Les plages sont de canard-types .NETIEnumerable
est distribué de façon dynamique. Et s'il vous plaît noter que les plages, pour tous leurs avantages, ne sont pas encore canonique façon de faire les choses dans la Norme C++.IEnumerator
n'est pas canard tapé. C++ les itérateurs et les plages ont pas de fonctions virtuelles. Duck-typing est 100% pertinent, parce que c'est la raison pour laquelle C++ les itérateurs et les plages n'ont pas besoin d'hériter d'une classe de base commune. Oh, le C#dynamic
mot clé n'est pas la même que la distribution dynamique, comme votre commentaire suggère. C'est de liaison dynamique. Qui est, d'ailleurs, encore plus lente que la distribution dynamique, même avec le DLR cache.IEnumerable
) et très élevés pour la dynamique de liaison (qui est la seule forme de "duck typing" que le C# a). Le langage de conception de C++ a un fort accent sur la prévention de l'exécution des coûts. Dynamisme est de la sémantique. S'il vous plaît arrêter d'abuser le terme de dynamic dispatch - il est synonyme de virtual expédition, pas de liaison dynamique. Duck-typing en C# besoins de liaison dynamique. Et enfin, la question est à proposIEnumerable
, ce qui n'est pas canard tapé.yield return
(vous n'avez jamais réellement besoin de mettre en œuvre IEnumerable manuellement, sauf si vous êtes en train de faire quelque chose de vilain). Comment voulez-vous faire l'équivalent en C++?yield return
... mais c'est vraiment une coroutine la mise en œuvre et n'a rien à voir avec accès au conteneur. Les normes C++ comité est à la recherche à différents coroutine implémentations; certains ont même expérimentales mises en œuvre dans les différents compilateurs. Mais il n'y a rien de normalisé le long de ces lignes.whatever_container<unique_ptr<Base>>
et efficacement à pied du conteneur, alors que pratiquement expédition sur ses éléments de trop.La norme C++ façon est de passer deux itérateurs:
Exemple de code client:
Yay programmation générique!
std::begin
etstd::end
.begin
et.end
donc il ne fait pas la cote ici. Dans tous les cas, la genericity desome_function
est ce qui est important et ce choix dans le code du client n'a pas d'incidence sur sa mise en œuvre.IEnumerable
en C#, c'est très facile, il vous suffit d'utiliseryield return
-- mais comment faire l'équivalent en C++?)IEnumerable<T>
est conceptuellement très différent devector
.La
IEnumerable
fournit avant uniquement, en lecture seule accès à une séquence d'objets, indépendamment de ce que le conteneur (le cas échéant) détient les objets. Unvector
est en fait un conteneur lui-même.En C++, si vous souhaitez donner l'accès à un conteneur sans donner les détails de ce conteneur, la convention est de passer en deux itérateurs représentant le début et la fin du conteneur.
Un bon exemple est le C++ STL définition de accumuler, qui peut être comparé avec le IEnumerable<T>.Agrégation
En C++
En C#
yield return
est. Cette question n'a pas d'accent sur le côté de mise en œuvre ou la consommation de côté, il pose des questions sur l'interface iterator lui-même, et pas des emballages pratiques. Vous êtes d'imposer votre curiosité au sujet de la mise en œuvre, ce qui est naturel, mais pas utile. Si vous voulez connaître les détails de mise en œuvre, demandez à votre propre question, ne pas détourner celui-ci.Si nous nous en tenons à la question strictement la réponse est non, autant que je sache. Les gens ont répétait qu'est-ce que le substitut disponible en C++, qui peut être de bonnes infos, mais pas de réponses, et que les OP plus en savait probablement déjà.
Je suis complètement en désaccord que "il n'est pas nécessaire," il est juste que les dessins de le C++ et .NET bibliothèques standards sont différents. La principale caractéristique de IEnumerable<>, c'est que c'est polymorphe, et il permet à l'appelant de faire usage de quelque classe qu'il veut (tableau, Liste, Ensemble, etc.), tout en continuant à fournir au moment de la compilation taper fort, fail-safe, même dans la bibliothèque d'Api.
La seule alternative en C++ est des modèles. Mais les modèles C++ ne sont pas en sécurité tapé au moment de l'exécution des génériques, ils sont en gros les macros. Alors tout d'abord avec les templates en C++, vous êtes obligé de fournir l'ensemble du modèle de code source pour celui qui a besoin d'utiliser votre modèle. D'ailleurs si vous faites votre bibliothèque API basées sur des modèles de vous perdre la capacité de garantir qu'un appel à compiler, et le code n'est pas automatiquement l'auto-documentation.
Je compatis pleinement avec toute autre programmeur qui utilise à la fois le C# et C++ et est frustré à ce point.
Cependant, C++2X est prévu d'ajouter des fonctionnalités, y compris les plages (qui peuvent satisfaire aux exigences de l'OP?); ainsi que les concepts (qui adresse les faibles et mauvaise vérification de type de modèles -- faille admis par Bjarne Stroustrup lui-même), et les modules (qui peut ou ne peut pas aider à réduire la douleur de l'en-tête uniquement les modèles).