2012-03-08 7 views
11

Como dice la pregunta, me pregunto cuál es el motivo. Porque recibo un error cuando trato de obtener la distancia entre los iteradores const y los que no son const.¿Por qué std :: distance no funciona en la combinación de iteradores const y nonconst?

vector<int> v; 
auto it=v.begin(); 
auto cit=v.cbegin(); 
distance(it,cit); 


no matching function for call to ‘distance(__gnu_cxx::__normal_iterator<int*, std::vector<int> >&, __gnu_cxx::__normal_iterator<const int*, std::vector<int> >&) 

Desde mi limitada comprensión de los iteradores, no veo ninguna razón para que no debería funcionar.

Respuesta

19

Tiene un iterador mutable y un iterador constante en la llamada al std::distance, por lo que la deducción del argumento de la plantilla está fallando. Puede solucionar esto especificando explícitamente el argumento de la plantilla.

std::vector<int> v; 
auto i1 = v.begin(); 
auto i2 = v.cbegin(); 

auto dist = std::distance<std::vector<int>::const_iterator>(i1, i2); 
6

Esto se debe a std::distance() sólo toma un parámetro de plantilla:

template <class InputIterator> 
iterator_traits<InputIterator>::difference_type 
distance(InputIterator first, InputIterator last); 

Por lo tanto, first y last debe ser convertible en el mismo tipo, y la resolución de la plantilla por desgracia no considerará que vector<int>::iterator es convertible en vector<int>::const_iterator.

+0

hmm ¿por qué no solo crean plantillas con 2 plantillas param? ¿Es posible hacerlo en cpp core lang? Lo que estoy preguntando es ¿una decisión de diseño o una limitación de lengua? – NoSenseEtAl

+0

para ser claros, sé que pueden hacer plantillas con 2 plantillas paramétricas, pero me pregunto si entraría en conflicto con 1 plantilla param versión – NoSenseEtAl

+0

@NoSenseEtAl, yo diría que decisión de diseño. Es más simple de esa manera, y calcular la distancia entre iteradores de diferentes tipos (por ejemplo, un iterador de acceso aleatorio y un iterador directo) probablemente no sea algo que quieras hacer muy a menudo. De hecho, podría escribir una versión con dos argumentos de plantilla, pero ¿qué problema del mundo real resolvería? –

3

std::distance trabajará con esos dos iteradores lo que no funciona es la inferencia argumento de plantilla. El compilador intenta resolver qué tipo sustituir al primer argumento de plantilla y tiene dos posibles candidatos, lo que según el estándar termina en un error.

Puede hacer una de dos cosas, o bien comparar sólo iteradores del mismo tipo, o proporcionar el tipo de la plantilla:

std::distance<std::vector<int>::const_iterator>(v.begin(), v.cbegin()); 
4

Como todo el mundo dice, es porque std::distance sólo toma un tipo de iterador, y la deducción del argumento de la plantilla no puede elegir cuál debería ser (aunque solo uno de ellos es posible dado que iterator se convierte a const_iterator pero no vuelve).

podría valer la pena escribir una plantilla algo como esto:

template <typename Container> 
typename Container::const_iterator constify(const Container &, typename Container::iterator it) { 
    return it; 
} 

A continuación, se puede forzar la deducción plantilla de la siguiente manera:

std::distance(constify(v, it), cit); 

en lugar de escribir ese gran tipo long. El parámetro Container& es una pena, está ahí porque AFAIK Container no se puede deducir solo de un argumento iterador.

Cuestiones relacionadas