Ce problème survient lorsque j'ai essayé d'écrire un modèle de classe C++ avec ctor qui accepte "l'itérateur général". Je ne sais pas s'il est approprié d'utiliser Word general ici, mais ce que je veux dire, c'est qu'il peut accepter un itérateur comme un conteneur STL.
En d'autres mots, je suis confus au sujet de iterator . Il semble que tous les conteneurs STL aient le même type d'itérateur, alors quel est ce type? Est-ce juste un pointeur? Ou quelque chose de plus compliqué? Mais le conteneur STL accepte le pointeur normal.
(Je voudrais le comparer à Iterator<T>
dans Java
, ce qui est assez simple et c'est juste une classe)
En C++, un Iterator est un concept, pas un type concret (ou abstrait), mais un type any qui obéit à certaines règles iterator comme.
Par exemple, les itérateurs peuvent généralement être incrémentés ++i
. Ils peuvent être consultés (déréférencés) *i
pour obtenir la valeur vers laquelle ils pointent actuellement. Ce sont essentiellement des abstractions d'un pointeur.
Dans les conteneurs et les algorithmes de la bibliothèque standard, il existe différents types d'itérateurs dotés de propriétés différentes. Leurs propriétés sont énumérées ici:
https://en.cppreference.com/w/cpp/iterator
Ainsi, lors de l'écriture d'algorithmes en C++ acceptant les itérateurs, n'accepte généralement que les paramètres de modèle generic et utilise les propriétés d'itérateur appropriées dans la fonction. Le compilateur se plaindra si l'utilisateur transmet à votre fonction quelque chose qui n'obéit pas aux règles de l'itérateur:
template<typename Iterator>
void my_algorithm(Iterator begin, Iterator end)
{
for(; begin != end; ++begin)
std::cout << *begin << '\n';
}
Vous pouvez ajouter toute une série de vérifications spécifiques pour vous assurer que l'utilisateur a passé quelque chose de sensé, mais c'est trop large pour cette question.
Alors que les concepts actuellement, tels que Iterator , ne sont qu'un ensemble de propriétés sémantiques convenues dans la norme que les programmeurs doivent suivre, une solution plus complète qui formalisera de tels concepts (en code) est destiné à la prochaine version de la norme, C++ 20 .
Les itérateurs en tant que concept ont été créés avant que C++ ne soit devenu un standard.
C++ a commencé comme C avec des classes. De nouvelles fonctionnalités ont été ajoutées et un nombre croissant de personnes s’est intéressé à la langue.
Un travail très important s'appelait STL - la bibliothèque de modèles standard - écrite à l'origine par Stepanov et Lee. en 1994 chez Hewlett-Packard, maintenu plus tard par SGI.
Cette bibliothèque utilisait la métaprogrammation de modèles de C++ de manière tout à fait révolutionnaire. Il a été écrit pour permettre des performances quasi nues avec des types abstraits, avec des implémentations d’algorithmes dissociées des implémentations de conteneurs, pour des types presque arbitraires.
Dans ce document, l'itérateur était un concept. Un concept en C++ est une catégorie de types (un type de types que vous pourriez dire). Les concepts en C++ sont not imposés par le compilateur (à ce moment).
Un type satisfait à un concept s'il comporte les opérations requises et que ces opérations en respectent les règles.
Il existe une hiérarchie de concepts autour des itérateurs dans la STL et, plus tard, dans la norme C++. Ils vont du moins restrictif (un itérateur) au plus fort (un itérateur contigu en lecture-écriture à accès aléatoire) et forment un arbre.
Lorsqu'un algorithme de modèle demande un Iterator, il demande un type satisfaisant le concept d'Iterator (comme décrit dans la norme C++). Lorsqu'ils demandent un RandomAccessIterator, ils demandent un type qui réponde au concept RandomAccessIterator (qui inclut également le concept Iterator, le concept ForwardIterator et quelques autres).
Donc template<class ForwardIterator> void std::sort( ForwardIterator, ForwardIterator )
est une fonction modèle qui prend deux instances du même type qui répondent au concept ForwardIterator.
Les ForwardIterators doivent prendre en charge un certain nombre d'opérations (*it
, ++it
, bool b = it != it
, bool b = it == it
, etc.), supporter certains traits (iterator_traits<it>::iterator_category
, iterator_traits<it>::reference
, iterator_traits<it>::value_type
, etc.) et ces opérations doivent respecter certaines règles.
Si vous lui donnez un type satisfaisant pour RandomAccessIterator, std::sort
garantit de meilleures performances que s'il recevait une ForwardIterator
.
Un pointeur brut satisfait à la fois l'itérateur Forward RandomAccess sans que vous ne fassiez rien. std::vector<?>::iterator
satisfait également les deux, mais souvent ce n'est pas un pointeur brut (la bibliothèque std a fait du travail).
Les deux types - le pointeur brut et std::vector<?>::iterator
- sont généralement des types non liés. Le système de template et de traits de C++ permet aux types sans relation d'être compris par le même algorithme de template avec une surcharge de temps d'exécution de zéro.
Dans c ++ 2a , il est prévu d'introduire des concepts dans le langage qui vérifient certaines des exigences pour des éléments comme RandomAccessIterator et documentent en langage les autres exigences qui ne peuvent pas être vérifiées dans la pratique.
Vous êtes peut-être confus en étant habitué aux langages orientés objet. C++ prend en charge la programmation orientée objet, mais n'est pas un langage orienté objet. Il prend en charge le polymorphisme (traitement identique de plusieurs types), sans héritage basé sur les objets de plusieurs manières.
Dans un langage orienté objet, chaque itérateur hériterait d'un type d'itérateur abstrait. Les algorithmes interagissaient avec l'itérateur via cette interface abstraite, envoyant souvent des appels via une table de fonctions virtuelle. Des valeurs de ce type ne seraient pas possibles, car le code de l'algorithme serait compilé sans connaître le nombre d'octets utilisés par les itérateurs, de sorte qu'une indirection supplémentaire se produirait.
En C++, l'algorithme n'est pas une fonction tant que vous ne lui transmettez pas le type de l'itérateur. À ce stade, la fonction est personnalisée pour cet itérateur. La norme C++ stipule que si l'itérateur fait certaines choses (obéit au concept requis), la fonction écrite par le modèle aura un certain comportement.
Cette fonction de modèle écrit permet de connaître la taille de l'itérateur, son fonctionnement, de les aligner et de stocker les instances de l'itérateur dans des mémoires tampons ou sur la pile en tant que valeur. À moins que l'itérateur ne le force, il n'y a pas de dispatch virtuel et, si les opérations sont visibles, elles peuvent être intégrées à la fonction écrite.
Le compilateur peut examiner les boucles serrées et la vectorisation peut se produire, comme si vous écriviez la fonction à la main.
Le même modèle peut trier des entrées de base de données, des chaînes ou des entiers. chaque cas, une nouvelle fonction est écrite, et le compilateur est invité à essayer de l'accélérer.
Les itérateurs ne sont pas un type; ils sont une sorte de type. Des types complètement non liés peuvent être des itérateurs. Il n'y a pas de classe de base pour les itérateurs; il y a juste certaines manières qu'ils garantissent qu'ils se comportent.
Les algorithmes C++ génèrent un code personnalisé pour chaque type d'itérateur que vous passez à std::sort
; si vous triez un vecteur de int et un vecteur de chaînes, aucun code binaire n'est partagé entre les deux (sauf la possibilité d'un repliement complet).Les concepts (type de type) Iterator/ForwardIterator/RandomAccessIterator sont des exigences documentées sur les types transmis aux algorithmes C++. Aucune application n'est effectuée, sauf que le compilateur est libre de faire littéralement n'importe quoi si vous ne remplissez pas les conditions requises.
The concepts (kind of type) Iterator/ForwardIterator/RandomAccessIterator are documented requirements on the types passed to the C++ algorithms. No enforcing is done, other than that the compiler is free to do literally anything if you fail to meet the requirements.
Itérateur est un modèle de conception comportemental décrit dans le cadre du "Groupe de quatre modèles". Cela résout un problème d'itération sur des objets dans un objet agrégé sans connaître la structure interne de cet objet.
Voir ci-dessous pour plus de détails sur le modèle d'itérateur: http://www.blackwasp.co.uk/Iterator.aspx