14

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

Community
  • 1
  • 1
Christian Ammer
  • 7,464
  • 6
  • 51
  • 108

1 Answers1

18

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!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • Yes this helps, thank you. The returned index now is 1 in both cases which seems right but it would be great if the result of the reverse find would give an index of 2. I cannot subtract `begin` from `rfound` because this leads to the same error as before. – Christian Ammer Jun 19 '13 at 21:35
  • @ChristianAmmer- I think that's because your logic to get the index is wrong. Your subtraction computes the distance from the reverse iterator to the last element of the array, which gives the distance *from the back* of the array, not from the front. – templatetypedef Jun 19 '13 at 21:36
  • I think I got it now. The logic was wrong but with `(end - begin) - (rfound - std::reverse_iterator(end)) - 1` I get the correct index. – Christian Ammer Jun 19 '13 at 21:47