2014-12-19 4 views
5

Ich muss eine std :: -Funktion an einen Algorithmus übergeben. Die Art der Funktion istKann ich std :: bind verwenden, um einen Status an eine Funktion anzuhängen?

typedef std::function<bool(const double&)> Condition; 

Im einfachsten Fall diese Funktion wie diese

bool simpleCondition(const double& d){return d<0.001;} 

aussehen Nun möchte ich den gleichen Zustand zu übergeben, aber nur dann, wenn die Bedingung mehrere Male erfüllt in eine Zeile, sollte die Funktion wahr zurückgeben. Ich habe folgendes versucht

class RepeatingCondition{ 
    public: 
     static Condition getRepeatingCondition(Condition c,int reps){ 
      return std::bind(&RepeatingCondition::evalCondition, 
            RepeatingCondition(c,reps),_1); 
     } 
    private: 
     RepeatingCondition(Condition cc,int reps) : counter(0), 
               reps(reps),cond(cc){} 
     bool evalCondition(const double& d){ 
      if (cond(d)){counter += 1;} 
      else {counter = 0;} 
      return (counter >= reps); 
     } 
     Condition cond; 
     int counter,reps; 
}; 

Mein Compiler klagen nicht und es scheint zu funktionieren wie erwartet. Allerdings verstehe ich nicht wirklich warum (mit einem einfachen Funktionszeiger würde es nicht funktionieren, oder?). Außerdem würde ich gerne wissen, ob es einen einfacheren Weg gibt, dasselbe zu erreichen.

+0

Mit einem Lambda: 'statische Bedingung getRepeatingCondition (Bedingung c, int Wiederholungen) {int counter = 0; return [=] (double const d) änderbar {return if (c (d)) counter + = 1; else counter = 0; Rückkehrzähler> = Wiederholungen; }} ' – dyp

+1

Beachten Sie, dass Sie den obigen Code vereinfachen können, indem Sie' RepeatingCondition :: evalCondition' in 'operator()' umbenennen, öffentlich machen und 'std :: bind (RepeedigCondition (c, reps), _1)' verwenden in 'getRepeatingCondition'. – dyp

+0

Ist eine statische Methode mit einem statischen Zähler nicht in Frage? Das könnte die Dinge ein wenig vereinfachen und es Ihnen ermöglichen, das Objekt vollständig zu entfernen. Hinweis: Ich behaupte nicht, dass dies die beste Lösung ist, da ich Ihre anderen Anwendungsfälle nicht kenne. – AndyG

Antwort

8

Kann ich std::bind verwenden, um einen Status an eine Funktion anzuhängen?

Ja, genau dafür ist es da. Sie gibt ein Objekt (eines nicht angegebenen Klassentyps) zurück, das den Funktionszeiger und alle gebundenen Argumente enthält, mit einem Funktionsaufruf operator(), um die Funktion mit diesen Argumenten aufzurufen.

std::function kapselt dann dieses Objekt ein und ermöglicht es, dass es herumgereicht und aufgerufen wird, ohne seinen Typ zu kennen. Diese Technik ist bekannt als Typ Löschung.

mit einem einfachen Funktionszeiger würde es nicht funktionieren, oder?

In der Tat brauchen Sie etwas komplizierter dafür zu arbeiten. Genau das bieten std::bind und std::function.

Auch würde ich gerne wissen, ob es einen einfacheren Weg, um das gleiche zu erreichen ist.

Ein Lambda ist oft besser lesbar als ein Binde Ausdruck:

static Condition getRepeatingCondition(Condition c,int reps){ 
    RepeatingCondition rep(c,reps); 
    return [rep](double d) mutable {return rep.evalCondition(d);}; 
} 
+0

Um fair zu sein, könnte ein einfacher Funktionszeiger funktionieren, wenn Sie eine statische Variable hinzufügen würden. Z.B. 'bool rep() {statischer int counter = 0; Rückgabe (Zähler ++> 5);} oder etwas. Natürlich würden Sie zusätzliche Logik innerhalb der Funktion benötigen, um die Variable zurückzusetzen, wenn Sie sie mehrmals verwenden wollten. – cartographer

+0

@cartographer: Das würde nur eine einzige Instanz erlauben (mit seltsamen Verhalten, wenn Sie eine zweite erstellt haben). –

+0

Ich habe nicht gesagt, dass es eine gute Idee ist, offensichtlich sollte man einen Ansatz bevorzugen wie in Ihrer Antwort, nur dass wenn es aus irgendeinem Grund nicht möglich ist, es andere Wege gibt. – cartographer

1

Da @ Mike Seymour bereits die Lambda-Ansatz hat, werde ich eine alternative Verwendung functors vorzuschlagen, die eine gute Alternative sein könnte der Code in der Frage:

class RepeatingCondition { 
    Condition m_condition; 
    int  m_counter, m_reps; 

public: 
    RepeatingCondition(Condition c, int reps) 
    : m_condition(c), m_counter(0) , m_reps(reps) { } 

    bool operator()(const double d) { 
     if(m_codition(d)) { 
      m_counter += 1; 
     } else { 
      m_counter = 0; 
     } 

     return (m_counter >= m_reps); 
    } 
}; 

Jetzt können Sie die Instanz erstellen Sie die RepeatingCondition Klasse verwenden möchten, etwa so:

RepeatingCondition repCond(checkDouble, 12); 

if(repCond(5.4)) { // calls the operator() overload 
    std::cout << "condition met\n"; 
} 
+0

ist das C++ 11? Ich habe gerade begonnen, die coolen neuen Sachen zu mögen, aber jetzt bin ich gezwungen, in einer Umgebung zu arbeiten, in der ich C++ 11 nicht benutzen kann :( – user463035818

+0

Sorry für die späte Antwort. Zum Glück ist das nicht C++ 11, also Sie können es ohne Probleme verwenden! –

Verwandte Themen