c++ - pairs - ¿Por qué la biblioteca estándar tiene find y find_if?
vector c++ (4)
Ciertamente puede implementar find
en términos de find_if
usando algún tipo de predicado de igualdad.
Supongo que la verdadera razón es que puede implementar find
bastante fácilmente y proporcionar implementaciones especializadas eficientes para tipos típicos encontrados; si está utilizando find_if
, el predicado que pase puede ser arbitrariamente complejo, lo que le da al implementador de la biblioteca un menor alcance de optimización.
Además, C ++ tiene la filosofía de "no pagas por lo que no usas" y normalmente esperarías que no pagues por una evaluación de predicados si lo harías con una simple comparación.
No se pudo find_if
solo fuera una sobrecarga de find
? Así es como std::binary_search
y amigos lo hacen ...
No puede tener el mismo nombre porque habría una ambigüedad. Supongamos que tenemos una sobrecarga de find
lugar de find_if
. Entonces supongamos:
// Pseudo-code
struct finder
{
bool operator()(const T&) const { ... }
bool operator==(const finder& right) const { ... }
}
std::vector<finder> finders;
finder my_finder;
std::find(finders.begin(), finders.end(), my_finder);
El find
no tendría forma de resolver la incoherencia: ¿debería intentar encontrar el finder
en el contenedor o usar el finder
para realizar la operación de búsqueda? Para resolver este problema, crearon dos nombres de funciones.
Un predicado es algo válido de encontrar, por lo que podría llegar a ambigüedades.
Considera find_if
se renombra el find
, entonces tienes:
template <typename InputIterator, typename T>
InputIterator find(InputIterator first, InputIterator last, const T& value);
template <typename InputIterator, typename Predicate>
InputIterator find(InputIterator first, InputIterator last, Predicate pred);
Qué se debe hacer, entonces, con:
find(c.begin(), c.end(), x); // am I finding x, or using x to find?
En lugar de tratar de encontrar una solución intrincada para diferenciar basada en x
(que no siempre se puede hacer *), es más fácil separarlos.
* Esto sería ambiguo, no importa cuál sea su esquema o cuán poderoso pueda ser †:
struct foo
{
template <typename T>
bool operator()(const T&);
};
bool operator==(const foo&, const foo&);
std::vector<foo> v = /* ... */;
foo f = /* ... */;
// f can be used both as a value and as a predicate
find(v.begin(), v.end(), f);
† Guarda la lectura mental.
Esto es lo que Stroustrup dijo (The C ++ Programming Language, 18.5.2):
Si
find()
yfind_if()
tuvieran el mismo nombre, habrían resultado aberraciones sorprendentes. En general, el sufijo_if
se usa para indicar que un alrigma toma un predicado.
En cuanto a qué es exactamente esa "ambigüedad", Steve Jessop respondió eso en su respuesta (mejor calificada) a esta pregunta SO .
(nota: esa pregunta en realidad puede calificar como la misma pregunta que esta. No soy lo suficientemente inteligente en C ++ arcania para decidir).