2010-02-03 7 views
7

Estoy creando un constructor que tomará un par de iteradores de entrada. Quiero que la firma del método para tener tiempo de compilación const semántica similar a:¿Cómo requiero semantics const_iterator en una firma de función de plantilla?

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

Sin embargo, no puedo encontrar ningún ejemplo de esto. Por ejemplo, el constructor de mi rango de aplicación de STL para vector se define como:

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

que no tiene tiempo de compilación const garantías. iterator_category/iterator_traits<> no contienen nada relacionado con const, tampoco.

¿Hay alguna manera de indicar para garantizar al llamante que no puedo modificar los datos de entrada?

edición, 2010-02-03 16:35 UTC

Como un ejemplo de cómo me gustaría utilizar la función, me gustaría ser capaz de pasar un par de punteros char* y saber, en función de la firma de la función, los datos a los que apuntan no se modificarán.
Esperaba poder evitar crear un par de punteros const char* para garantizar la semántica de const_iterator. Puedo ser obligado a pagar el impuesto de plantilla en este caso.

+0

¿Es este el tipo de cosas para las cuales los conceptos aplicados por el compilador serían buenos? No recuerdo si la propuesta decía algo acerca de los requisitos de const. – mskfisher

+0

Creo que la mejor opción posible en este momento es crear una instancia explícita de la función usando 'const char *' y confiar en eso como mi verificación en tiempo de compilación para todos los demás tipos. – mskfisher

Respuesta

2

simplemente podría crear una función ficticia que llama a su plantilla con char * const punteros. Si su plantilla intenta modificar sus objetivos, entonces su función ficticia no se compilará. A continuación, puede poner dicho maniquí dentro de las guardias #ifndef NDEBUG para excluirlo de las versiones de lanzamiento.

+0

Esto es más parecido. Esto me da la seguridad en tiempo de compilación que estaba buscando. – mskfisher

+0

... aunque para mis propósitos, creo que quiere decir punteros 'const char *'. – mskfisher

+0

Sí - Doh! ¡Cuenta! –

2

¿Qué hay 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); 
} 
+0

Evita la deducción de parámetros de plantilla mediante el uso de tipos internos. –

+0

Buena idea, pero no tengo un const_iterator aquí porque paso dos 'char *' como iteradores. – mskfisher

+0

Agregue una sobrecarga para un par de punteros. – UncleBens

0

que Vector constructor está recibiendo sus argumentos por valor, lo que significa que los iteradores de quien llama se copian antes de ser utilizados en el constructor, que por supuesto significa que no pasa nada a los iteradores de quien llama.

const para argumentos de entrada solo importa cuando pasa por referencia. p.ej.

void foo(int& x)

vs

void foo(const int& x)

En el primer ejemplo, la entrada del llamante para x puede ser modificado por foo. En el segundo ejemplo, puede que no, ya que la referencia es const.

+0

Lo siento, no estaba completamente claro en mi pregunta. Quiero asegurarme de que los datos a los que apuntan los iteradores están garantizados para ser tratados como const, no que los iteradores en sí deberían ser const. – mskfisher

+1

Un const_iterator no se puede usar para modificar el elemento del contenedor que está iterando. Un iterador ordinario * puede * usarse de esa manera, incluso si se pasa por referencia constante. (Simplemente haga una copia no const.) Los tipos 'const iterator' y' const_iterator' no son las mismas cosas. –

9

El que llama puede simplemente usar la plantilla con const iterators. Si lo hace, y el compilador no se queja, se garantiza que la función no modifique los datos. Si modificaría los datos, crear una instancia de la plantilla con un iterador de const derivaría en errores.

Realmente no tiene que forzar la persona que llama para utilizar iteradores const simplemente porque no modifica nada.

+0

+1 ... ¡y decir que me tomé la molestia de indicar cómo hacerlo! –

+0

La semántica del ejemplo 'DataObject' significa que puedo pasar punteros que no son' 'conformes y que se los trate como punteros' const'. No quiero * obligar * a la persona que llama a utilizar iteradores 'const'. Solo quiero garantizar que solo se utilizarán * como iteradores' const'. – mskfisher

+0

O bien hace copias defensivas de los datos para que no cambien (const char * interno), o documenta sus requisitos y continúa con vida. – KitsuneYMG

0

Esto es fácil (pero no bastante) si no puede pagar impulso:

#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 
} 

EDITAR: si usted quiere tener e indicación acerca de esto en su firma, entonces es común para explotar el nombre de la parámetro de plantilla:

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

Según tengo entendido, el objetivo de la pregunta es solo asegurarme de que la función en sí misma no puede modificar la secuencia. El punto no es forzar al usuario a lanzar cosas manualmente a los iteradores. – UncleBens

+0

Como dije en mi comentario a @sth, quiero solicitar que el iterador se pueda * usar * como const_iterator, al igual que un iterador de acceso aleatorio se puede usar como un iterador directo. – mskfisher

Cuestiones relacionadas