2013-06-19 13 views
9

Per cercare la prima occorrenza di un elemento in un array C con elementi POD, una facilità può farlo con std::find_if(begin, end, findit). Ma avevo bisogno dell'ultima apparizione. This answer mi ha dato l'idea che questo può essere fatto con std::reverse_iterator. Così ho provato:Come si usa find_if insieme a reverse_iterator su un array in stile C?

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

questo mi ha dato l'errore:

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

Avete un idea di come farlo in questo modo o sapete una soluzione migliore?

Questo è il codice:

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

E il compiler error on codepad.org

risposta

11

La funzione std::find_if ha un tipo di ritorno uguale al tipo di iteratore passato come parametro. Nel tuo caso, dal momento che stai passando a std::reverse_iterator<xyz*> s come parametri, il tipo di reso sarà std::reverse_iterator<xyz*>. Ciò significa che

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

non si compila, perché found è un xyz*.

Per risolvere questo problema, si può provare questo:

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

Questo sarà correggere l'errore del compilatore. Tuttavia, penso che voi due errori secondari di questa linea:

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

In primo luogo, si noti che si dispone di un punto e virgola dopo l'istruzione if, in modo che il corpo della dichiarazione if saranno valutate indipendentemente dal fatto che la condizione è vera .

In secondo luogo, si noti che std::find_if restituisce il secondo iteratore come sentinella se il nulla corrisponde al predicato. Di conseguenza, questa prova deve essere

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

perché find_if tornerà std::reverse_iterator<xyz*>(begin) se l'elemento non viene trovato.

Spero che questo aiuti!

+0

Sì questo aiuta, grazie. L'indice restituito ora è 1 in entrambi i casi, il che sembra giusto, ma sarebbe bello se il risultato della ricerca inversa desse un indice di 2. Non posso sottrarre 'begin' da' rfound' perché questo porta allo stesso errore di prima . –

+0

@ ChristianAmmer - Penso che sia perché la tua logica per ottenere l'indice è sbagliata. La sottrazione calcola la distanza dall'iter iter inverso all'ultimo elemento dell'array, che fornisce la distanza * dal retro * dell'array, non dalla parte anteriore. – templatetypedef

+0

Penso di averlo capito ora. La logica era sbagliata ma con '(fine - inizio) - (rfound - std :: reverse_iterator (fine)) - 1' Ottengo l'indice corretto. –

Problemi correlati