2010-02-03 11 views
7

Sto creando un costruttore che prenderà una coppia di iteratori di input. Voglio la firma del metodo di avere in fase di compilazione const semantica simile a:Come si richiede la semantica const_iterator in una firma di funzione modello?

DataObject::DataObject(const char *begin, const char *end) 

Tuttavia, non riesco a trovare alcun esempio di questo. Per esempio, il costruttore gamma di mia implementazione STL per vector è definito come:

template<class InputIterator> 
vector::vector(InputIterator first, InputIterator last) 
{ 
    construct(first, last, iterator_category(first)); 
} 

che non ha tempo di compilazione const garanzie. iterator_category/iterator_traits<> non contengono nulla in relazione allo const.

C'è un modo per indicare per garantire al chiamante che non posso modificare i dati di input?

modificare, 2010-02-03 16:35 UTC

Come esempio di come vorrei utilizzare la funzione, mi piacerebbe essere in grado di passare un paio di char* puntatori e sapere, in base alla firma della funzione, che i dati a cui puntano non verranno modificati.
Speravo di evitare di creare un paio di puntatori const char* per garantire la semantica di const_iterator. In questo caso potrei essere costretto a pagare la tassa modello.

+0

È questo il tipo di cosa a cui i concetti imposti dal compilatore sarebbero utili? Non ricordo se la proposta dicesse qualcosa sui requisiti const. – mskfisher

+0

Penso che la migliore opzione possibile a questo punto sia di istanziare esplicitamente la funzione usando un 'const char *' e fare affidamento su di esso come controllo di compilazione per tutti gli altri tipi. – mskfisher

risposta

2

si potrebbe semplicemente creare una funzione fittizia che chiama il modello con char * const puntatori. Se il tuo modello tenta di modificare i loro target, la tua funzione dummy non verrà compilata. È quindi possibile inserire detto dummy all'interno delle protezioni #ifndef NDEBUG per escluderlo dalle versioni di rilascio.

+0

Questo è più simile. Questo mi dà l'assicurazione della durata della compilazione che stavo cercando. – mskfisher

+0

... anche se per i miei scopi, penso che intendiate i puntatori di 'const char *'. – mskfisher

+0

Sì - Doh! Conto! –

2

cosa circa

#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); 
} 
+0

Si impedisce la deduzione dei parametri del modello utilizzando i tipi interni. –

+0

Buona idea, ma non ho un const_iterator qui perché sto passando due 'char *' come iteratori. – mskfisher

+0

Aggiungi un sovraccarico per una coppia di puntatori. – UncleBens

0

Tale vettore costruttore riceve i suoi argomenti per valore, il che significa che iteratori del chiamante vengono copiati prima di essere utilizzati nel costruttore, che ovviamente significa che non succede nulla iteratori del chiamante.

const per gli argomenti di input importa solo quando si passa per riferimento. per esempio.

void foo(int& x)

vs

void foo(const int& x)

Nel primo esempio, l'ingresso del chiamante per x può essere modificata dal foo. Nel secondo esempio, potrebbe non farlo, poiché il riferimento è const.

+0

Scusa, non ero completamente chiaro nella mia domanda. Voglio assicurarmi che i dati a cui gli iteratori puntano siano trattati come const, non che gli iteratori stessi debbano essere const. – mskfisher

+1

Un const_iterator non può essere utilizzato per modificare l'elemento del contenitore che sta iterando. Un iteratore ordinario * può * essere usato in questo modo, anche se è passato per riferimento const. (Basta fare una copia non const di esso.) I tipi 'const iterator' e' const_iterator' non sono le stesse cose. –

9

Il chiamante può semplicemente utilizzare il modello con iteratori const. Se lo fa, e il compilatore non si lamenta, è garantito che la funzione non modifica i dati. Se modificasse i dati, l'istanziazione del modello con un iteratore const causerebbe errori.

In realtà non è necessario forza il chiamante per utilizzare iteratori const solo perché non si modifica nulla.

+0

+1 ... e per dire che ho avuto il problema di indicare come farlo! –

+0

La semantica dell'esempio 'DataObject' significa che posso passare dei puntatori non-' '' '' '' '' '' '' e li ho trattati come puntatori 'const'. Non voglio * forzare * il chiamante a usare 'const' iterators - Voglio solo garantire che saranno * usati * come' iteratori const '. – mskfisher

+0

O fate copie difensive dei dati in modo che non cambino (const const interno *), oppure documentate le vostre esigenze e procedete con la vita. – KitsuneYMG

0

Questo è facile (ma non abbastanza) se lo può permettere spinta:

#include <boost/static_assert.hpp> 
#include <boost/type_traits.hpp> 

template<class It> 
void f(It b, It e) 
{ 
    using namespace boost; 
    typedef typename std::iterator_traits<It>::reference reference; 
    BOOST_STATIC_ASSERT(is_const<typename remove_reference<reference>::type>::value); 
} 

void test() 
{ 
    f((char const*)0, (char const*)0); // Compiles 
    f((char*)0, (char*)0); // Does not compile 
} 

EDIT: se si vuole avere e l'indicazione su questo nella tua firma, allora è comune a sfruttare il nome del modello di parametro:

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

Come ho capito il punto della domanda è solo per assicurarsi che la funzione stessa non possa modificare la sequenza. Il punto non è forzare l'utente a lanciare manualmente le cose su iteratori const. – UncleBens

+0

Come ho detto nel mio commento a @sth, voglio richiedere che l'iteratore possa * essere * usato come const_iterator, proprio come un iteratore di accesso casuale può essere usato come iteratore diretto. – mskfisher