2011-12-16 15 views
9

Estoy escribiendo una envoltura delgada plantilla para iteradores, y chocó contra un obstáculo a su paso por el operador de la estructura de eliminar la referencia, sobre todo porque los punteros no tienen uno:Estructura operador eliminar la referencia (del operador>)

#include <vector> 

struct mystruct { 
    int member; 
}; 

template<class iterator> 
struct wrap { 
    typedef typename std::iterator_traits<iterator>::pointer pointer; 
    iterator internal; 
    pointer operator->() {return internal.operator->();} //MARK1 
}; 

int main() { 
    wrap<std::vector<mystruct>::iterator> a; 
    a->member; 
    wrap<mystruct*> b; 
    b->member; 
    return 0; 
} 

http://ideone.com/XdvEz

prog.cpp: In member function ‘typename std::iterator_traits<_Iter>::pointer wrap<iterator>::operator->() [with iterator = mystruct*]’: 
prog.cpp:18: instantiated from here 
prog.cpp:11: error: request for member ‘operator->’ in ‘((wrap<mystruct*>*)this)->wrap<mystruct*>::internal’, which is of non-class type ‘mystruct*’ 

Esto siguiente método funciona, pero creo que no se garantiza que funcione. A saber, si un iterador tiene un tipo extraño pointer que no es lo mismo que un puntero a value_type.

pointer operator->() {return &*internal;} //MARK3 
+1

¿Qué versión de C++ tiene una estructura de operador * * eliminar la referencia? –

+0

¿Por qué 'char *'? ¿No habría algún tipo de 'Iterator :: value_type' en alguna parte? –

+3

@ThomasMatthews: Eso es lo que [wikipedia] (http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Member_and_pointer_operators) lo llama. El estándar de C++ simplemente lo llama 'operator->'. –

Respuesta

10

La norma indirecta dice que una sobrecarga operator-> tiene que o devolver un puntero, un objeto que se puede convertir en un puntero o un objeto que ha sobrecargado operator->. Su mejor opción es simplemente devolver internal.

§13.5.6 [over.ref] p1

Una expresión x->m se interpreta como (x.operator->())->m

(Lo anterior se aplica de forma recursiva.)

+0

Y antes de preguntar sobre 'operator *()', el tipo de retorno es 'iterator_traits :: reference' y devuelve simplemente' * iterator'. Cualquier iterador que no devuelva una 'referencia' en la desreferencia no modela correctamente el concepto del iterador y puede ignorarse. – Xeo

+0

Sí, obtuve 'operator *', pero nunca me di cuenta de que debía devolver 'iterator' en lugar de' puntero'. ¡Gracias! Espero que esta sea la respuesta, pero trataré de darle un día más o menos para otras sugerencias. –

+0

Solo agregaría, que la recursión termina cuando se devuelve un puntero (o un objeto convertible en un puntero), de modo que si el operador-> devuelve un puntero, usted golpea el caso base de recursión y listo. Si el operador-> devuelve algo más con una sobrecarga de operador->, usted recurse. Esto puede parecer obvio, pero me tomó un tiempo resolverlo. –

Cuestiones relacionadas