2010-10-19 13 views
20

Mi pregunta es segura, simple para cualquiera que esté familiarizado con la sintaxis de C++. Solo estoy aprendiendo C++ y esta es una especie de de deberes.¿Cómo recuperar el tipo de valor del iterador en C++?

template<typename Iter> 
void quickSort(Iter begin, Iter end) 
{   
    //.. 
    auto pivot = * (begin + (end - begin)/2); 
    //.. 
} 

Se supone que el pivote contiene valores desde el centro del intervalo [begin, end]. Ite El código que escribí allí funciona, pero auto es una palabra clave del nuevo estándar del lenguaje. ¿Cómo hacerlo a la vieja usanza? ¿Qué escribir en lugar de auto?

+18

Eso es lo que me gusta ver. Alguien que acaba de aprender C++, usando iteradores y 'auto'. :) – jalf

Respuesta

23

typename std::iterator_traits<Iter>::value_type

Esto funcionará si la plantilla se crea una instancia con Iter como un tipo de puntero. Por favor, typename no es parte del tipo en sí. Le dice al compilador que value_type realmente es un tipo. Si era el nombre de una función o un miembro de datos estáticos, entonces eso afecta la sintaxis. El compilador no necesariamente sabe de qué se trata, ya que la especialización de iterator_traits para Iter puede no estar visible cuando se compila la plantilla.

+1

Esta es la mejor solución posible, pero vale la pena señalar que no es una solución general. No se garantiza que funcione con todo lo que un usuario pueda intentar pasar como un iterador ... es posible que aún necesiten agregar value_type a su objeto iterador (o crear una especialización para los rasgos). Una alternativa es simplemente continuar utilizando iteradores y crear un iterador en el pivote, desreferenciando según sea necesario, sin necesidad del tipo de valor dentro de la función de plantilla. –

+3

@Tony: es cierto, y 'auto' es mejor por esa razón. Sin embargo, todos los algoritmos estándar requieren que el usuario pase algo que tenga 'iterator_traits' (24.3.1), y es razonable que las plantillas de funciones definidas por el usuario tengan la misma restricción. Las personas que escriben iteradores pueden usar 'std :: iterator' como una clase base para cerrar la brecha entre * intentar * pasar en un iterador, y en realidad pasar un' Iterator' ;-) –

+1

@Steve: sí, absolutamente (y ya tienes un +1 de mí). –

1

La respuesta de Steve es correcta; en C++ 98, debe usar std :: iterator_traits o puede usar Iter :: value_type si sabe que el iterador tiene este typedef (por ejemplo, se deriva de std :: iterator). Sin embargo, hay otro problema en su código: normalmente no puede simplemente dividir iteradores. Esto funciona con punteros, por supuesto, pero no en el caso más general. Un enfoque más general sería:

Iter itPivot = std::advance(begin, std::distance(begin, end)/2); 
+0

El código original no divide los iteradores, y esto no funcionaría, ni siquiera con los punteros. En su lugar, el código usa la resta, que funciona en todos los iteradores de acceso aleatorio (no solo en los punteros). Y dado que quicksort se ordenará para otros tipos de iteradores de todos modos (una implementación eficiente de todos modos), el uso de 'operator -' aquí está bien. –

Cuestiones relacionadas