Les exigences relatives aux conteneurs sont passées de C++ 03 à C++ 11. Alors que C++ 03 avait des exigences générales (par exemple, la constructibilité de la copie et l'attribution pour le vecteur), C++ 11 définit des exigences précises pour chaque opération de conteneur (section 23.2).
En conséquence, vous pouvez par exemple stocker un type qui est constructible par copie mais non assignable - comme une structure avec un membre const - dans un vecteur tant que vous n'effectuez que certaines opérations qui ne nécessitent pas d'affectation (construction et Push_back
sont de telles opérations; insert
ne l'est pas).
Ce que je me demande, c'est: est-ce que cela signifie que la norme permet désormais vector<const T>
? Je ne vois aucune raison pour laquelle cela ne devrait pas - const T
, tout comme une structure avec un membre const, est un type qui est constructible en copie mais non assignable - mais j'ai peut-être manqué quelque chose.
(Une partie de ce qui me fait penser que j'ai peut-être manqué quelque chose, c'est que le tronc gcc se bloque et brûle si vous essayez d'instancier vector<const T>
, mais ça va avec vector<T>
où T a un membre const).
Non, je crois que les exigences d'allocateur disent que T peut être un "type d'objet non const, non référence".
Vous ne pourriez pas faire grand-chose avec un vecteur d'objets constants. Et un const vector<T>
Serait presque le même de toute façon.
Plusieurs années plus tard, cette réponse rapide et sale semble toujours attirer des commentaires et des votes. Pas toujours debout. : -)
Donc, pour ajouter quelques références appropriées:
Pour la norme C++ 03, que j'ai sur papier, le tableau 31 dans la section [lib.allocator.requirements] dit:
T, U any type
Ce n'est pas que tout type ait réellement fonctionné.
Ainsi, la norme suivante, C++ 11, dit dans un brouillon proche dans [allocator.requirements] et maintenant le tableau 27:
T, U, C any non-const, non-reference object type
ce qui est extrêmement proche de ce que j'ai écrit à l'origine ci-dessus de mémoire. C'est aussi de cela qu'il s'agissait.
Cependant, en C++ 14 ( projet N4296 ) le tableau 27 dit maintenant:
T, U, C any non-const object type
Peut-être parce qu'une référence n'est peut-être pas un type d'objet après tout?
Et maintenant en C++ 17 ( draft N4659 ) c'est le tableau 30 qui dit:
T, U, C any cv-unqualified object type (6.9)
Ainsi, non seulement const
est exclu, mais aussi volatile
. Probablement de vieilles nouvelles de toute façon, et juste une clarification.
Veuillez également consulter informations de première main d'Howard Hinnant , actuellement juste en dessous.
Mise à jour
Sous la réponse acceptée (et correcte), j'ai commenté en 2011:
Conclusion: nous n'avons pas conçu de conteneurs pour contenir
const T
. Bien que j'y ai réfléchi. Et nous avons failli le faire par accident. À ma connaissance, le point de blocage actuel est la paire de fonctions membresaddress
surchargées dans l'allocateur par défaut: lorsqueT
estconst
, ces deux surcharges ont le même Signature. Un moyen simple de corriger cela serait de se spécialiserstd::allocator<const T>
et supprimez l'une des surcharges.
Avec le prochain projet de C++ 17, il me semble que nous avons maintenant légalisé vector<const T>
, et je crois aussi que nous l'avons fait accidentellement. :-)
P0174R supprime les surcharges address
de std::allocator<T>
. P0174R ne fait aucune mention du support std::allocator<const T>
dans le cadre de sa justification.
Correction
Dans les commentaires ci-dessous T.C. note correctement que les surcharges address
sont obsolètes, non supprimées. Ma faute. Les membres déconseillés n'apparaissent pas au 20.10.9 où le std::allocator
est défini, mais est plutôt relégué à la section D.9. J'ai négligé de scanner le chapitre D pour cette possibilité lorsque j'ai posté cela.
Merci T.C. pour la correction. J'envisageais de supprimer cette réponse trompeuse, mais peut-être est-il préférable de laisser cette correction de côté afin que peut-être cela empêche quelqu'un d'autre de mal interpréter la spécification de la même manière que moi.
Même si nous avons déjà de très bonnes réponses à ce sujet, j'ai décidé d'apporter une réponse plus pratique pour montrer ce qui peut et ce qui ne peut pas être fait.
Donc ça ne marche pas:
vector<const T> vec;
Lisez simplement les autres réponses pour comprendre pourquoi. Et, comme vous l'avez peut-être deviné, cela ne fonctionnera pas non plus:
vector<const shared_ptr<T>> vec;
T
n'est plus const
, mais vector
contient shared_ptr
s, pas T
s.
D'un autre côté, cela fonctionne fonctionne:
vector<const T *> vec;
vector<T const *> vec; // the same as above
Mais dans ce cas, const est l'objet pointé, pas le pointeur lui-même (qui est ce que le vecteur stocke). Cela équivaudrait à:
vector<shared_ptr<const T>> vec;
Ce qui est bien.
Mais si nous mettons const
à la fin de l'expression, cela transforme maintenant le pointeur en const
, donc ce qui suit ne se compile pas:
vector<T * const> vec;
Un peu déroutant, je suis d'accord, mais on s'y habitue.
En complément des autres réponses, une autre approche consiste à utiliser:
vector<unique_ptr<const T>> vec;
Si c'est le cas où vous souhaitez appliquer que seul vec
est propriétaire de ses éléments. Ou si vous voulez une dynamique de déplacement des éléments dans vec
et à un moment donné les déplacer.
Comme indiqué, la sémantique du pointeur const
peut prêter à confusion, mais shared_ptr
et unique_ptr
ne le sont pas. const unique_ptr<T>
est un pointeur const et unique_ptr<const T>
est une pointe constante comme on peut s'y attendre.