Hi I'm wondering how you would write a function that could iterate through any stl container so it didn't matter what you were using e.g list, vector, deque and found an item that matched in that list so the function declaration would look something like this

template <class TypeList, class Type>
Type findInContainer( TypeList< Type > list, Type item )

//where the return value is the index of where it was found
template <class TypeList, class Type>
int findInContainer( TypeList< Type > list, Type item, Type& itemFound )

//My code later on both filled with values

std::deque< int > dequeContainer;
std::vector< std::string > vectorContainer

int foundNumber = -1;
int index = findInContainer( dequeContainer, 20, foundNumber );

I was wondering how this is achieved using templates.
Returning the item found would be used for some property in the item lets say it was a list of objects that have an id and it was trying to find the item based on the id

Any help would be appreciated.
Thanks

Recommended Answers

All 6 Replies

I am aware of find and iterators however I am more curious if it is possible to pass containers into the template function and if possible how this is done.

Containers are permitted as template arguments. Consider:

template < typename T, class E >
bool contains (const T& haystack, const E& needle) {
    typename T::const_iterator F = haystack.begin(), L = haystack.end();
    for (; F != L; ++F)
        if (*F == needle)
            return true;
    return false;
}

You can use that like:

std::vector< std::string > v;
    std::deque< int > d;
    
    // ...

    if (contains (v, std::string("foo")))
        std::cout << "v contains 'foo'" << std::endl;
    if (contains (d, 42))
        std::cout << "d contains 42" << std::endl;

    //...

Of course, this can not be applied across the board since something like a std::map iterates over std::pair s and there is no operator== for a std::pair .

Thanks L7Sqr that's exactly what I was wondering. How would this work with objects i.e in your example needle. If needle was some object that had an id and a name for example. Is it possible to access the variables of the generic object to check against each other

if( (*F)->id == needle->id )
{
  return *F;
}  

return NULL;

Is something like the above possible?

Yes. Though, my example used references so the -> operator would not work (unless it was a pointer type you passed in). For example:

template < typename T, class E >
bool contains (const T& haystack, const E& needle) {
    typename T::const_iterator F = haystack.begin(), L = haystack.end();
    for (; F != L; ++F)
        if (F->get() == needle.get())
            return true;
    return false;
}

struct Foo {
    int i_;
    Foo (int i) : i_(i) {}
    int get() const { return i_; }
};

int main () {

    std::vector< Foo > v;

    v.push_back (Foo(42));

    if (contains (v, Foo(42)))
        std::cout << "v contains Foo(42)" << std::endl;
    if (contains (v, Foo(43)))
        std::cout << "v contains Foo(43)" << std::endl;

    return 0;
}

Realize that this is now only applicable to types that define int get() . The more things required of the types in a templated definition the less generic that definition becomes.

I realise that you were using references instead of pointers sorry I should have mentioned that above. Thanks for answering all my questions. I think I understand now basically any method being called in the templated function must have a definition in the object that has being called. That's why doing things like overloading the == operator make it more generic and I can't use maps the same as deques vectors etc.
Thanks again.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.