2010-08-08 2 views
5

Gerade jetzt, ich habe diesen Code:vereinfachen einfachen C++ Code - so etwas wie Pythons jeden

bool isAnyTrue() { 
    for(std::list< boost::shared_ptr<Foo> >::iterator i = mylist.begin(); i != mylist.end(); ++i) { 
     if((*i)->isTrue()) 
      return true; 
    } 

    return false; 
} 

I-Boost hier verwendet habe und dann, aber ich konnte nicht wirklich einfache Art und Weise erinnern, es zu schreiben etwas wie ich würde es in Python vielleicht schreiben, zB:

def isAnyTrue(): 
    return any(o.isTrue() for o in mylist) 

gibt es irgendein Konstrukt in STL/Boost, es zu schreiben mehr oder weniger wie das?

Oder vielleicht ein Äquivalent zu diesem Python-Code:

def isAnyTrue(): 
    return any(map(mylist, lambda o: o.isTrue())) 

Meistens frage ich mich, ob eine bestehende any ist (und all) gleichwertig in-Boost/STL noch. Oder warum nicht (weil es ziemlich nützlich scheint und ich es oft in Python verwende).

Antwort

6

C++ hat (noch) kein foreach Konstrukt. Sie haben zu schreiben, dass sich/

Das heißt, Sie std::find_if Algorithmus hier verwenden können:

bool isAnyTrue() 
{ 
    return std::find_if(mylist.begin(), mylist.end(), std::mem_fun(&Foo::isTrue)) 
      != mylist.end(); 
} 

Außerdem sollten Sie wahrscheinlich eher mit std::vector oder std::deque als std::list.

EDIT: sth hat mich gerade informiert, dass dies nicht wirklich kompilieren, weil Ihre Liste enthält shared_ptr anstelle der tatsächlichen Objekte ... aus diesem Grund, sind Sie müssen Deins eigenen Funktor zu schreiben, oder Verlass auf Boost:

//#include <boost/ptr_container/indirect_fun.hpp> 

bool isAnyTrue() 
{ 
    return std::find_if(mylist.begin(), mylist.end(), 
      boost::make_indirect_fun(std::mem_fun(&Foo::isTrue))) != mylist.end(); 
} 

Hinweis, ich habe diese zweite Lösung nicht getestet.

+0

@sth: Wie ist diese Lösung? –

+0

Boost hat eine foreach ('BOOST_FOREACH'). – Albert

+0

@ Albert: Ja, tut es. Aber selbst in diesem Fall sollten Sie Algorithmusaufrufe zu expliziten Schleifen bevorzugen. –

4

Anstelle von find_if würde ich mit einem benutzerdefinierten gehen. Ich mag es besser in Bezug auf die Lesbarkeit über find_if, aber das ist Geschmackssache.

template<class ForwardIterator, class Pred> 
bool any(ForwardIterator begin, ForwardIterator end, Pred pred) { 
    for(; begin != end; ++begin) 
    if(pred(*begin)) return true; 

    return false; 

    //or 
    //return std::find_if(mylist.begin(), mylist.end(), std::mem_fun(&Foo::isTrue)) 
    //  != mylist.end(); 

} 

bool isAnyTrue() { 
    return any(mylist.begin(), mylist.end(), std::mem_fun(&Foo::isTrue)); 
} 

Bearbeiten: Alternative alle mit find_if von Billy ONeal.

+1

Nichts ist falsch mit einem Brauch, aber warum nicht implementieren es in Bezug auf 'find_if'? –

+0

Ok, nun, ich habe mich meistens gefragt, warum es in Boost noch kein solches 'irgendwas' (oder etwas ähnliches) gibt. Dies ist meistens so, wie ich es bereits getan habe (nicht in meiner Frage, sondern in meinem echten Code), mit einer eigenen eigenen 'any'-Funktion. – Albert

+0

@Albert - Das coole an dieser Version von any() ist, dass es Vorlagen verwendet und mit (keinem Wortspiel beabsichtigt) jedem Typ funktioniert. Es ist etwas, das Sie in Ihr Programmierwerkzeug stecken und überall verwenden können. –

4

Der neue C++ Standard hat std :: any_of, z.B.

bool isAnyTrue() 
{ 
    return std::any_of(mylist.begin(), mylist.end(), std::mem_fn(&Foo::isTrue)); // Note std::mem_fn and not std::mem_fun 
} 

VS2010 hat dies implementiert.

+1

g ++ 4.4 implementiert dies auch. – rafak

+0

& rafak: Bitte Links angeben! –

+0

Das erste Ergebnis in Google. http://msdn.microsoft.com/en-us/library/ee396393.aspx – ronag