10

I have a class CMyVector which holds a vector of pointers to CMyClass objects and I have several "find" functions to find elements according to differente criteria. So for example, I have:

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

At first, they were implemented as loops, traversing the vector, looking for the element that matches X, str, ptr or whatever. So I've created predicates, like this one:

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

And ended with a bunch of functions which all look like this:

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

They all look the same, except for the predicate that is called, so I've thought of simplifying more, and created a function like this one:

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

And do:

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

And so on.

So my question is: How should I declare my Find function so I can pass it my predicates? I've tried several ways, but with no luck so far.

MikMik
  • 3,426
  • 2
  • 23
  • 41
  • You can wrap the template find in another template as suggested or use `const std::function&` as predicate parameter. – AJG85 Dec 05 '11 at 15:31

1 Answers1

13

use template to take in whatever ever type you need

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

You could alway also use 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;
}

Personally I prefer the top one, because it will probably be easier for the compiler to optimize as there is less indirection. and if the call is unique it might get inlined.

EDIT: It is also worth noting that if go you with the templated option, you will have to provide the implementation in the header file, this can be a pain. Whereas the std::function can live in the source (.cpp) file with all the other implementations.

111111
  • 15,686
  • 6
  • 47
  • 62