2013-06-19 6 views
9

Um das erste Vorkommen eines Elements in einem C-Array mit POD-Elementen zu suchen, kann man dies mit std::find_if(begin, end, findit) tun. Aber ich brauchte das letzte Vorkommnis. This answer gab mir die Idee, dass dies mit std::reverse_iterator getan werden kann. So habe ich versucht:Wie benutzt man find_if zusammen mit reverse_iterator auf einem C-artigen Array?

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

Dies gab mir den Fehler:

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

Haben Sie eine Idee, wie es auf diese Art und Weise zu tun, oder kennen Sie eine bessere Lösung?

Dies ist der 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; 
} 

Und die compiler error on codepad.org

Antwort

11

Die std::find_if Funktion einen Rückgabetyp gleich der Art von Iterator als Parameter übergeben in aufweist. In Ihrem Fall, da Sie std::reverse_iterator<xyz*> s als Parameter übergeben, ist der Rückgabetyp std::reverse_iterator<xyz*>. Das bedeutet, dass

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

wird nicht kompiliert, da found ein xyz* ist.

Um dies zu beheben, können Sie dies versuchen:

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

Dadurch wird der Compiler-Fehler beheben. Ich denke jedoch, dass Sie zwei sekundäre Fehler in dieser Zeile:

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

Beachten Sie zunächst, dass Sie ein Semikolon nach der if Anweisung haben, so dass der Körper der if Anweisung wird unabhängig davon beurteilt werden, ob die Bedingung erfüllt ist .

Zweitens notieren Sie, dass std::find_if den zweiten Iterator als Sentinel zurückgibt, wenn das Nichts mit dem Prädikat übereinstimmt. Folglich sollte dieser Test

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

sein, weil find_if wird std::reverse_iterator<xyz*>(begin) zurück, wenn das Element nicht gefunden wird.

Hoffe, das hilft!

+0

Ja, das hilft, danke. Der zurückgegebene Index ist jetzt in beiden Fällen 1, was richtig erscheint, aber es wäre großartig, wenn das Ergebnis des umgekehrten Auffindens einen Index von 2 ergeben würde. Ich kann nicht "beginnen" von "rfunden" subtrahieren, weil dies zu demselben Fehler wie zuvor führt . –

+0

@ ChristianAmmer- Ich denke, das ist, weil Ihre Logik, um den Index zu bekommen, falsch ist. Ihre Subtraktion berechnet den Abstand vom Rückwärts-Iterator zum letzten Element des Arrays, der den Abstand * von der Rückseite * des Arrays und nicht von vorne angibt. – templatetypedef

+0

Ich glaube, ich habe es jetzt. Die Logik war falsch, aber mit '(end - begin) - (rfound - std :: reverse_iterator (end)) - 1 'bekomme ich den richtigen Index. –