7
votes

Comment dois-je avoir besoin de la sémantique Const_iterator dans une signature de fonction de modèle?

Je crée un constructeur qui prendra une paire d'itérateurs d'entrée. Je veux la signature de la méthode d'avoir compilé Const Semantitique similaire à: xxx

Cependant, je ne peux trouver aucun exemples de ceci. Par exemple, le constructeur de la plage de mon implémentation de stl pour vecteur est défini comme suit: xxx

qui n'a pas de compilation-heure const Garanties. itérator_category / itérator_traits <> ne contient rien de ce qui concerne const , non plus.

existe-t-il un moyen d'indiquer pour garantir le appelant que je ne puisse pas modifier les données d'entrée?

EDIT, 2010-02-03 16:35 UTC

comme exemple de la façon dont je voudrais J'aime utiliser la fonction, je voudrais pouvoir passer une paire de points d'affichage char * et savoir, en fonction de la signature de fonction, que les données qu'elles pointent ne seront pas modifiées.
J'espérais que je puisse éviter de créer une paire de «indicatifs> Const» des pointeurs pour garantir la sémantique Const_iterator. Je suis peut-être obligé de payer la taxe de gabarit dans ce cas.


2 commentaires

Est-ce le genre de chose que les concepts forcés compilateurs seraient bons? Je ne me souviens pas si la proposition a annoncé quoi que ce soit sur les exigences de Cons-Cons-ce.


Je pense que la meilleure option possible à ce stade est d'instancier explicitement la fonction à l'aide d'un const char * et comptez sur celui-ci en vérification de mon compilation pour tous les autres types.


5 Réponses :


2
votes

Qu'en est-il de

#include <vector>

template <class T>
class MyClass{
public:
    MyClass(typename T::const_iterator t1,typename T::const_iterator t2){
    }
    // *EDITED*: overload for pointers (see comments)
    MyClass(const T* t1,const T* t2){
    }
};

void main(){
    std::vector<int> v;
    std::vector<int>::const_iterator it1 = v.begin();
    std::vector<int>::const_iterator it2 = v.end();
    MyClass<std::vector<int> > mv(it1,it2);

    // with pointers:
    char* c1;
    char* c2;
    MyClass mc(c1,c2);
}


2 commentaires

Vous empêchez la déduction du paramètre de modèle en utilisant des types internes.


Bonne idée, mais je n'ai pas de const_iterator ici parce que je passe dans deux char * comme itérateurs.



0
votes

Ce constructeur de vecteur reçoit ses arguments par valeur, ce qui signifie que les itérateurs de l'appelant sont copiés avant d'être utilisés dans le constructeur, ce qui signifie bien sûr que rien ne se passe sur les itérateurs de l'appelant.

const pour les arguments d'entrée seulement comptent vraiment lorsque vous passez à titre de référence. E.g.

void foo (int & x)

vs

void foo (const int & x)

Dans le premier exemple, l'entrée de l'appelant pour x peut être modifiée par foo . Dans le deuxième exemple, ce n'est peut-être pas, car la référence est const .


2 commentaires

Désolé, je n'étais pas complètement clair dans ma question. Je tiens à nous assurer que les données pointant par les itérateurs sont garanties pour être traitées comme constant, non pas que les itérateurs eux-mêmes devraient être constitués.


Un const_iterator ne peut pas être utilisé pour modifier l'élément du conteneur qu'il est itération. Un itérateur ordinaire peut être utilisé de cette façon, même si elle est adoptée par la référence de const. (Faites simplement une copie sans const.) Les types const itérateur et const_iterator ne sont pas les mêmes choses.



10
votes

L'appelant peut simplement utiliser le modèle avec des itérateurs des constants. S'il le fait, et le compilateur ne se plaint pas, il est garanti que la fonction ne modifie pas les données. Si cela modifierait les données, l'instanciation du modèle avec un itérateur de Const entraînerait des erreurs.

Vous n'avez pas vraiment à la force l'appelant pour utiliser les itérateurs constants simplement parce que vous ne modifiez rien.


10 commentaires

+1 ... et dire que je suis arrivé à tout le problème d'indiquer comment le faire!


La sémantique de l'exemple dataObject signifie que je peux passer dans des pointeurs non const et les avoir traités comme des pointeurs const . Je ne veux pas force l'appelant à utiliser const itérateurs - je veux juste garantir qu'ils ne seront utilisés comme const itérateurs.


Soit vous faites des copies défensives des données afin qu'il ne change pas (interne Cons-FR *) ou vous documentez vos exigences et activez-la avec la vie.


C'est ca le truc. J'essaie d'obtenir la signature de la fonction à la fois de documenter et de défendre, comme je peux faire avec les paramètres Const Char * .


@mskfisher: Il ne sert à rien de sortir de votre part. Pour la documentation, appelez simplement le paramètre Template Paramètre Constituteur, si vous devez, testez que la fonction compile si elle est donnée des itérateurs des constants et d'avancer.


@Unclebens: Je pense que le vôtre est la bonne réponse, pourquoi ne le postez-vous pas séparément?


Je pense que c'est exactement ce que dit qc sth. (Et il peut y avoir des gens ici, cela reviendrait une telle réponse, ce qui, pour eux, semble dire "juste ignorer la constance de la correction". :))


Je pense que ce que l'oncleben ajoute, ce qui peut-être que STH figurings va sans dire, est testé que le modèle compile si donné des itérateurs de const. Si vous examinez votre implémentation de la bibliothèque standard, vous verrez probablement qu'aucun des algorithmes standard ne vérifie explicitement qu'ils utilisent uniquement les capacités que leurs paramètres de modèle sont définis, mais vous pouvez être à peu près sûr qu'ils sont testés avec «Minimalement Capable "Itérateurs aussi près que possible. Les interfaces cochées explicites pour les modèles sont des concepts pour les concepts et les concepts sont si difficiles à obtenir que 10 ans n'étaient pas assez longs ;-).


@mskfisher Si vous avez besoin d'un const char * , je peux passer dans un char * et il est favorisé à const char * . Si vous avez besoin d'un Char * , je ne peux pas passer est un const char * Becuase const ne peut pas être emporté implicitement. Je pense que la plupart de l'en-tête CSTString a Const Char * pour les paramètres de source, mais l'appelant peut toujours passer dans char *


@kts, c'est exactement ce que je vais, mais je veux aussi pouvoir passer dans un vecteur :: iterator . Cependant, il n'ya aucun moyen de constituer - promouvoir un itérateur lors de la transmission d'un paramètre de modèle. Spécifiquement, il n'y a aucun moyen de lancer génériquement à partir d'un aléatoire_access_itéator à un INPUT_ITERATOR (qui sont la sémantique que je vais dans ce cas).



0
votes

Ceci est facile (mais pas joli) si vous pouvez vous permettre de booster: xxx pré>

modifier em>: Si vous voulez avoir et indiquer à ce sujet dans votre signature alors Il est courant d'exploiter le nom du paramètre Modèle: P>

template<class ConstIt>
void f(ConstIt b, ConstIt e)
...


2 commentaires

Si je comprends bien, le point de la question est de vous assurer que la fonction elle-même ne peut pas modifier la séquence. Le but n'est pas de forcer l'utilisateur à lancer manuellement des choses pour constituer des itérateurs.


Comme je l'ai dit dans mon commentaire à @sth, je veux exiger que l'itérateur puisse être utilisé en tant que const_iterator, comme un itérateur d'accès aléatoire peut être utilisé comme itérateur avant.



2
votes

Vous pouvez simplement créer une fonction factice qui appelle votre modèle avec char * const pointeurs. Si votre modèle tente de modifier leurs objectifs, votre fonction factice ne compilera pas. Vous pouvez ensuite mettre ledit mannequin à l'intérieur #ifndef ndebug pour l'exclure des constructions de version.


2 commentaires

C'est plus comme ça. Cela me donne l'assurance du temps de compilation que je cherchais.


... Bien que pour mes besoins, je pense que vous voulez dire Const Char * Pointeurs.