Как передать предикат в качестве параметра функции - PullRequest
8 голосов
/ 05 декабря 2011

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

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

Сначала они были реализованы в виде циклов, пересекающих вектор, ищущих элемент, который соответствует X, str, 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, чтобы я мог передать ей свои предикаты? Я пробовал несколько способов, но пока безуспешно.

1 Ответ

10 голосов
/ 05 декабря 2011

используйте шаблон для ввода любого нужного вам типа

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

Вы также можете использовать std :: function (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;
}

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

РЕДАКТИРОВАТЬ: Стоит также отметить, что если вы используете шаблонную опцию, вам придется предоставить реализацию в заголовочном файле, это может быть проблемой. Принимая во внимание, что функция std :: function может находиться в исходном (.cpp) файле со всеми другими реализациями.

...