c++ templates overloading

c++ - ¿Cómo funciona la selección de función de plantilla sobrecargada(coincidencia de patrones) en std:: vector insert?



vector insert c++ (5)

Considere las siguientes declaraciones de un std :: vector (tomadas de cplusplus - EASTL tiene las mismas declaraciones)

iterator insert ( iterator position, const T& x ); void insert ( iterator position, size_type n, const T& x ); template <class InputIterator> void insert ( iterator position, InputIterator first, InputIterator last );

Si escribo

someVector.insert(someVector.begin(), 10, 90);

¿por qué no se confunde (por el compilador) con la última sobrecarga, donde 10 y 90 son int s y el tipo InputIterator se toma como int lugar de la alternativa que es tomar 10 como size_type y 20 como const int& ?

Ahora digo "no" porque estoy implementando un contenedor vectorial (con fines de aprendizaje) y, en mi caso, con la llamada mencionada anteriormente, la tercera sobrecarga es seleccionada por el compilador en lugar de la segunda sobrecarga y, en consecuencia, no se compila. Si elimino la tercera sobrecarga, entonces las cosas parecen estar bien.

¿Tiene algo que ver con lo que llama la última sobrecarga (funciones sobrecargadas con rasgos de iterador)? Si es así, si asumiera que todos los iteradores son punteros en bruto (aunque en mi caso estoy usando la misma declaración, eso significa que tengo una sobrecarga # 3 con una plantilla que espera un iterador ... aunque espera que sea lo incorrecto Palabra aquí porque al final puede ser cualquier cosa y en este caso, se interpreta como int para mí y no compila) ¿cómo me aseguraré de que el compilador seleccione la función adecuada?


23.1.1 / 9 dicta que debe elegir el constructor "tipo / valor integral" en lugar del constructor "iterador / iterador" y el compilador debe asegurarse de que sea capaz de tomar esa determinación.

[Texto estándar]:

El miembro funciona en las formas:

template <class InputIterator> // such as insert() rt fx1(iterator p, InputIterator f, InputIterator l); template <class InputIterator> // such as append(), assign() rt fx2(InputIterator f, InputIterator l); template <class InputIterator> // such as replace() rt fx3(iterator i1, iteraror i2, InputIterator f, InputIterator l);

Tendrá el mismo efecto, respectivamente, como:

fx1(p, static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l)); fx2(static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l)); fx3(i1, i2, static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l));

si InputIterator es un tipo integral.


En su caso, la inserción coincide con la plantilla mejor que con la no plantilla, siempre que sus parámetros sean int e int .

¡El estándar requiere que funcione como si la no plantilla fuera seleccionada de todos modos!

- El miembro funciona en las formas:

template <class InputIterator> // such as insert()
rt fx1(iterator p, InputIterator f, InputIterator l);

template <class InputIterator> // such as append(), assign()
rt fx2(InputIterator f, InputIterator l);

template <class InputIterator> // such as replace()
rt fx3(iterator i1, iteraror i2, InputIterator f, InputIterator l);

Tendrá el mismo efecto, respectivamente, como:

fx1(p, static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l)); fx2(static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l)); fx3(i1, i2, static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l));

si InputIterator es un tipo integral.

Así que tiene que haber algo de magia mágica para resolver esto.

Si cambia su llamada a someVector.insert(someVector.begin(), 10u, 90); , la no plantilla será la mejor coincidencia, dependiendo de qué tipo de size_type sea.


Es probable que la implementación aplique SFINAE, que en algunos casos tiene un mandato estándar, para garantizar que InputIterator sea en realidad un iterador. Además de eso, el compilador solo creará una instancia de la versión de la plantilla si no puede hacer una llamada a ninguna plantilla.


Kerrek está en el camino correcto. Los autores de cplusplus.com parecen estar mirando algo distinto de gcc. Si dieran un vistazo a gcc, verían que está salpicado de comentarios como // 438. Ambiguity in the "do the right thing" clause .

C ++ 1998/2003, como cualquier estándar, tiene su cuota de errores. Míralo de esta manera: ¿Alguna vez has escrito (genérico tú) una pieza de código perfecta de cualquier tamaño, un documento perfecto de cualquier tipo? Las normas no son inmunes. Están escritos por personas. Al menos hay una posibilidad de detectar automáticamente errores en el código que escribes: puedes compilarlo, ejecutar algunas herramientas en su contra. ¿Cómo vas a revisar un documento de normas?

Los estándares son desarrollados por el comité. Algunas de las actualizaciones a la norma anterior fueron una amalgama de esquemas no estándar competidores de diferentes proveedores. Otras actualizaciones fueron conceptos nuevos que, aunque circularon en todo el comité de estándares, se validaron mediante un control de escritorio. Es sorprendente para mí que el estándar actual tenga tan pocos errores como lo hace.


Por curiosidad, eché un vistazo a las fuentes del CCG:

template<typename _InputIterator> void insert(iterator __position, _InputIterator __first, _InputIterator __last) { // Check whether it''s an integral type. If so, it''s not an iterator. typedef typename std::__is_integer<_InputIterator>::__type _Integral; _M_insert_dispatch(__position, __first, __last, _Integral()); }

Luego...

// _GLIBCXX_RESOLVE_LIB_DEFECTS // 438. Ambiguity in the "do the right thing" clause template<typename _Integer> void _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val, __true_type) { _M_fill_insert(__pos, __n, __val); } // Called by the range insert to implement [23.1.1]/9 template<typename _InputIterator> void _M_insert_dispatch(iterator __pos, _InputIterator __first, _InputIterator __last, __false_type) { typedef typename std::iterator_traits<_InputIterator>:: iterator_category _IterCategory; _M_range_insert(__pos, __first, __last, _IterCategory()); }

Parece que, de hecho, estaban preocupados de que pudiera surgir una ambigüedad, por lo que se utiliza un uso explícito de las actividades tipográficas y la sobrecarga para verificar si la plantilla coincide con un tipo integral o no.