2010-04-16 7 views
6

Estoy confundido acerca de la interfaz de std::find. ¿Por qué no toma un objeto Compare que le dice cómo comparar dos objetos?¿Cómo se std :: encontrar utilizando un objeto Compare?

Si pudiera pasar un objeto Compare que podría hacer el siguiente código de trabajo, donde me gustaría comparar por valor, en lugar de sólo la comparación de los valores del puntero directamente:

typedef std::vector<std::string*> Vec; 
Vec vec; 
std::string* s1 = new std::string("foo"); 
std::string* s2 = new std::string("foo"); 
vec.push_back(s1); 
Vec::const_iterator found = std::find(vec.begin(), vec.end(), s2); 
// not found, obviously, because I can't tell it to compare by value 
delete s1; 
delete s2; 

¿La siguiente la forma recomendada ¿para hacerlo?

template<class T> 
struct MyEqualsByVal { 
    const T& x_; 
    MyEqualsByVal(const T& x) : x_(x) {} 
    bool operator()(const T& y) const { 
    return *x_ == *y; 
    } 
}; 
// ... 
vec.push_back(s1); 
Vec::const_iterator found = 
    std::find_if(vec.begin(), vec.end(), 
       MyEqualsByVal<std::string*>(s2)); // OK, will find "foo" 

Respuesta

6

find no se puede sobrecargar para tomar un predicado unario en lugar de un valor, porque es un parámetro de plantilla no restringida. Entonces, si llama al find(first, last, my_predicate), existiría una ambigüedad potencial si quiere que el predicado sea evaluado en cada miembro del rango, o si quiere encontrar un miembro del rango que sea igual al predicado en sí (podría ser un rango de predicados, para todos los diseñadores de las bibliotecas estándar, saber o importar, o el value_type del iterador podría ser convertible tanto al tipo de predicado como a su argument_type). De ahí la necesidad de find_if para ir bajo un nombre diferente.

find podría haberse sobrecargado para tomar un predicado binario opcional, además del valor buscado. Pero capturar valores en funtores, como lo has hecho, es una técnica tan estándar que no creo que sea una ganancia masiva: ciertamente nunca es necesario, ya que siempre puedes lograr el mismo resultado con find_if.

Si obtuvo el find que deseaba, igual tendría que escribir un funtor (o usar boost), ya que <functional> no contiene nada para desreferenciar un puntero. Sin embargo, su functor sería un poco más simple como predicado binario, o podría usar un puntero de función, por lo que sería una ganancia modesta. Entonces no sé por qué esto no se proporciona. Dado el fiasco copy_if no estoy seguro de que haya mucho valor en suponer que siempre hay buenas razones para los algoritmos que no están disponibles :-)

+0

Gracias! Por curiosidad, ¿qué pasa con 'copy_if'? – Frank

+1

@dehmann: Lo único malo es que no está en el estándar. Se excluyó esencialmente debido a un accidente de edición. –

2

Desde su T es un puntero, es posible que así almacenar una copia del puntero en el objeto función.

Aparte de eso, así es como se hace y no hay mucho más que eso.

Como un lado, no es una buena idea almacenar punteros en un contenedor, a menos que sea extremadamente cuidadoso al garantizar la seguridad de las excepciones, que es casi siempre más complicada de lo que vale.

+0

Y ... me perdí la primera mitad de la pregunta ... oops. Sin embargo, la respuesta de Steve Jessop es mejor de lo que podría haber explicado de todos modos. –

0

Eso es exactamente para lo que find_if es, se necesita un predicado para comparar elementos.

Cuestiones relacionadas