2011-12-05 41 views
8

Tengo una clase CMyVector que contiene un vector de punteros a objetos CMyClass y tengo varias funciones "buscar" para encontrar elementos de acuerdo con diferentes criterios. Así, por ejemplo, que tengo:Cómo pasar predicado como parámetro de función

CMyClass* CMyVector::FindByX(int X); 
CMyClass* CMyVector::FindByString(const CString& str); 
CMyClass* CMyVector::FindBySomeOtherClass(CSomeOtherClass* ptr); 
// Other find functions... 

Al principio, se implementaron como bucles, atravesando el vector, buscando el elemento que coincide con X, str, ptr o lo que sea. Así que he creado predicados, como éste:

class IsSameX:public unary_function<CMyClass*, bool> 
{ 
    int num; 
public: 
    IsSameX(int n):num(n){} 
    bool operator()(CMyClass* obj) const 
    { 
     return (obj != NULL && (obj->X() == num)); 
    } 
}; 

y terminó con un montón de funciones que todo este aspecto:

CMyClass* CMyVector::FindByX(int x) 
{ 
    CMyVector::iterator it = find_if(vec.begin(), vec.end(), IsSameX(x)); 
    if (it != vec.end()) 
    { 
     return *it; 
    } 
    return NULL; 
} 

Todos ellos tienen el mismo aspecto, excepto por el predicado que es llamada, por lo que he pensado de simplificar más, y creé una función como ésta:

CMyClass* CMyVector::Find(ThisIsWhatIDontKnow Predicate) 
{ 
    CMyVector::iterator it = find_if(vec.begin(), vec.end(), Predicate); 
    if (it != vec.end()) 
    { 
     return *it; 
    } 
    return NULL; 
} 

y NO:

CMyClass* CMyVector::FindByX(int x) 
{ 
    return Find(IsSameX(x)); 
} 

Y así sucesivamente.

Así que mi pregunta es: ¿Cómo debo declarar mi función Find para que pueda pasarle mis predicados? Lo intenté de varias maneras, pero sin suerte hasta el momento.

+0

Puede envolver la plantilla encontrar en otra plantilla como se sugiere o usar 'const std :: function &' como parámetro de predicado. – AJG85

Respuesta

10

uso plantilla para tomar en cualquier que sea el tipo que necesita

template<typename UnaryPredicate> 
CMyClass* CMyVector::Find(UnaryPredicate Predicate) 
{ 
    CMyVector::iterator it = find_if(vec.begin(), vec.end(), Predicate); 
    if (it != vec.end()) 
    { 
     return *it; 
    } 
    return NULL; 
} 

Usted podría también utilizar todos los días std :: función (C++ 11)

CMyClass* CMyVector::Find(std::function<bool(const (CMYClass*)&)> Predicate) 
{ 
    CMyVector::iterator it = find_if(vec.begin(), vec.end(), Predicate); 
    if (it != vec.end()) 
    { 
     return *it; 
    } 
    return NULL; 
} 

personalmente prefiero el de arriba, porque probablemente sea más fácil para el compilador optimizar ya que hay menos direccionamiento indirecto. y si la llamada es única, se puede incluir en línea.

EDITAR: También vale la pena señalar que, si elige la opción de plantilla, tendrá que proporcionar la implementación en el archivo de encabezado, esto puede ser un problema. Mientras que la función std :: puede vivir en el archivo fuente (.cpp) con todas las demás implementaciones.

+0

Gracias, todavía no tengo C++ 11, así que tendré que seguir el camino de la plantilla. – MikMik

Cuestiones relacionadas