2011-12-05 1 views
8

У меня есть класс CMyVector, который содержит вектор указателей на объекты CMyClass, и у меня есть несколько функций «найти» для поиска элементов в соответствии с разными критериями. Так, например, у меня есть:Как передать предикат как функциональный параметр

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

Сначала они были выполнены в виде петель, пересекающий вектор, ищет элемент, который соответствует X, ул, PTR или любой другой. Таким образом, я создал предикаты, как этот:

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)); 
    } 
}; 

И закончилась с кучей функций, которые все выглядеть следующим образом:

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

все они выглядят одинаково, для предиката, который, кроме называется, поэтому я думал, что упрощать больше, и создал функцию, как этот:

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

и сделать:

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

И так далее.

Так что мой вопрос: Как мне объявить мою функцию Find, чтобы я мог передать ей свои предикаты? Я пробовал несколько способов, но пока не повезло.

+0

Вы можете обернуть поиск шаблона в другом шаблоне, как предложено, или использовать 'const std :: function &' в качестве параметра предиката. – AJG85

ответ

10

использовать шаблон, чтобы взять в любой когда-либо типа вам нужно

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; 
} 

Вы можете также использовать все дни зЬй :: функцию (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; 
} 

Лично я предпочитаю верхний один, потому что, вероятно, будет проще оптимизировать компилятор, поскольку существует меньше косвенности. и если вызов уникален, он может стать встроенным.

EDIT: Также стоит отметить, что если вы отправитесь с шаблоном, вам придется предоставить реализацию в файле заголовка, это может быть болью. В то время как std :: function может находиться в исходном файле (.cpp) со всеми другими реализациями.

+0

Спасибо, у меня еще нет C++ 11, поэтому мне придется идти по шаблону. – MikMik