How do you use find_if along with reverse_iterator on a C-style array?

Christian Ammer picture Christian Ammer · Jun 19, 2013 · Viewed 11.3k times · Source

To search the first occurence of a element in a C-Array with POD elements, one ease can do this with std::find_if(begin, end, findit). But I needed the last occurence. This answer gave me the idea that this can be done with std::reverse_iterator. Thus I tried:

std::find_if(std::reverse_iterator<podtype*>(end),
             std::reverse_iterator<podtype*>(begin),
             findit);

This gave me the error:

cannot convert 'std::reverse_iterator< xyz* > ' to 'xyz*' in assignment

Do you have an idea how to do it this way or do you know a better solution?

This is the code:

#include <iostream>
#include <iterator>
#include <algorithm>

struct xyz {
    int a;
    int b;
};

bool findit(const xyz& a) {
    return (a.a == 2 && a.b == 3);
}

int main() {
    xyz begin[] = { {1, 2}, {2, 3}, {2, 3}, {3, 5} };
    xyz* end = begin + 4;

    // Forward find
    xyz* found = std::find_if(begin, end, findit);
    if (found != end)
        std::cout << "Found at position "
                  << found - begin
                  << std::endl;

    // Reverse find
    found = std::find_if(std::reverse_iterator<xyz*>(end),
                         std::reverse_iterator<xyz*>(begin),
                         findit);
    if (found != std::reverse_iterator<xyz*>(end));
        std::cout << "Found at position "
                  << found - std::reverse_iterator<xyz*>(end)
                  << std::endl;

    return 0;
}

And the compiler error on codepad.org

Answer

templatetypedef picture templatetypedef · Jun 19, 2013

The std::find_if function has a return type equal to the type of iterator passed in as a parameter. In your case, since you're passing in std::reverse_iterator<xyz*>s as parameters, the return type will be std::reverse_iterator<xyz*>. This means that

found = std::find_if(std::reverse_iterator<xyz*>(end),
                     std::reverse_iterator<xyz*>(begin),
                     findit);

won't compile, because found is an xyz*.

To fix this, you can try this:

std::reverse_iterator<xyz*>
rfound = std::find_if(std::reverse_iterator<xyz*>(end),
                      std::reverse_iterator<xyz*>(begin),
                      findit);

This will fix the compiler error. However, I think that you two secondary errors in this line:

if (found != std::reverse_iterator<xyz*>(end));

First, note that you have a semicolon after the if statement, so the body of the if statement will be evaluated regardless of whether the condition is true.

Second, note that std::find_if returns the second iterator as a sentinel if the nothing matches the predicate. Consequently, this test should be

if (rfound != std::reverse_iterator<xyz*>(begin))

because find_if will return std::reverse_iterator<xyz*>(begin) if the element is not found.

Hope this helps!