2016-07-21 14 views
0

Ich habe ein wenig Mühe, einen Aufruf std :: bind zu verstehen. Im folgende Beispiel:Grundlegendes Bind

#include <functional> 
#include <iostream> 
#include <memory> 


class Notifier 
{ 
public: 
    Notifier(std::function<void(Notifier&)> on_notify) 
    :on_notify_(on_notify) 
    { } 

    void notify() 
    { 
     if (on_notify_) 
      on_notify_(*this); 
    } 

    std::function<void(Notifier&)> on_notify_; 

}; 

struct Manager 
{ 
    Manager() 
    { 
     n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this)); 
    } 

    void trigger() 
    { 
     std::cout << "notified" << std::endl; 
    } 

    std::unique_ptr<Notifier> n_; 
}; 

int main() 
{ 
    Manager s; 
    s.n_->notify(); 
} 

Ich verstehe nicht, wie on_notify_(*this); Anrufe den Funktor mit einem Notifier& Parameter zurück, aber der Funktor von bind erstellt es nicht geben. Die Aufrufe führen korrekt zu der void notify() Methode, aber ich verstehe nicht, was genau wird der Funktor von Bind erstellt werden, um dies zu erreichen.

Wenn ich stattdessen ein Lambda schreiben würde, müsste ich den Parameter angeben, sonst würde es kompilieren. Welche Art von Operation macht bind hier hinter meinem Rücken? :-)

+0

Es gibt einen Verweis auf die Eigenschaften des zurückgegebenen Typs [hier] (http://en.cppreference.com/w/cpp/utility/functional/bind). Insbesondere sein 'operator()'. – chris

+0

Könntest du ein bisschen mehr ausarbeiten? es scheint immer noch ein wenig obskur –

+2

@ dau_sama "Wenn einige der Argumente, die im Aufruf von g() angegeben werden, nicht durch Platzhalter in g ersetzt werden, werden die nicht verwendeten Argumente ausgewertet und verworfen." – immibis

Antwort

2

std::bind grundsätzlich ignoriert das ungültige angegebene Argument nach this.

Wenn einige der Argumente, die im Aufruf von g() übergeben werden, nicht mit in g gespeicherten Platzhaltern übereinstimmen, werden die nicht verwendeten Argumente ausgewertet und verworfen.

Es mag Sie überraschen, dass, wenn noch absurder Argumente zur Verfügung gestellt werden, kann der binded Funktors noch erfolgreich Manager::trigger() wie folgt erreichen:

#include <functional> 
#include <iostream> 
#include <memory> 

// Some classes that have nothing to do with on_notify_ 
class AAA {}; 
class BBB {}; 

class Notifier 
{ 
public: 
    Notifier(std::function<void(AAA&, BBB&)> on_notify) 
     :on_notify_(on_notify) 
    { } 

    void notify() 
    { 
     if (on_notify_) 
     { 
      // Arguments not matching. 
      AAA a{}; 
      BBB b{}; 

      // Invoke with them. 
      on_notify_(a, b); 
     } 
    } 

    std::function<void(AAA&, BBB&)> on_notify_; 
}; 

struct Manager 
{ 
    Manager() 
    { 
     n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this)); 
    } 

    void trigger() 
    { 
     std::cout << "it's also notified!" << std::endl; 
    } 

    std::unique_ptr<Notifier> n_; 
}; 

int main() 
{ 
    Manager s; 
    s.n_->notify(); 
} 

Live-Demo ist here.