2013-03-02 3 views
7

Quale costrutto dovrebbe essere utilizzato come surrogato per std::function<> quando C++ 11 non è disponibile?
L'alternativa dovrebbe fondamentalmente consentire l'accesso alle funzioni dei membri privati ​​di una classe da un'altra classe come nell'esempio seguente (non vengono utilizzate altre funzionalità di std :: function). La classe Foo è fissa e non può essere modificata molto, ho solo accesso alla classe Bar.Esiste qualcosa di simile a std :: function prima di C++ 11?

class Foo { 
    friend class Bar; // added by me, rest of the class is fixed 
    private: 

    void doStuffFooA(int i); 
    void doStuffFooB(int i); 
}; 

class Bar { 
    public: 

    Bar(Foo foo, std::function< void (const Foo&, int) > func) { 
    myFoo = foo; 
    myFooFunc = func; 
    }; 

    private: 

    doStuffBar(const &Foo foo) { 
    myFooFunc(foo, 3); 
    } 

    Foo myFoo; 
    std::function< void (const Foo&, int) > myFooFunc; 
} 

int main() { 

    Foo foo(...); 

    Bar barA(foo, &Foo::doStuffFooA); 

    Bar barB(foo, &Foo::doStuffFooB); 
    ... 
} 
+1

Questo codice non dovrebbero compilare, anche quando l'ovvio gli errori sintattici sono corretti. I due oggetti 'Bar' sono costruiti con i puntatori alle funzioni dei membri privati, ma il codice in cui ciò accade non ha accesso a quei membri. Questo non ha nulla a che fare con 'std :: function'; non arriva a violare le regole di accesso. –

risposta

10

C'è qualcosa di simile a std :: funzione prima di C++ 11?

. C'è Boost.Function (boost::function<>), che recentemente è diventato parte della libreria standard C++ e ha fornito un'implementazione di riferimento per std::function<>; allo stesso modo, Boost.Bind (boost::bind<>()) è stato adottato dallo standard ed è diventato std::bind<>().

Si implementa una tecnica chiamata cancellazione di tipo portaoggetti richiamabili di qualsiasi tipo. Ecco una possibile implementazione illustrativo di come un tale modello di classe potrebbe essere definita da zero (non usare nel codice di produzione, questo è solo un esempio):

#include <memory> 

template<typename T> 
struct fxn { }; 

template<typename R, typename... Args> 
struct fxn<R(Args...)> 
{ 

public: 

    template<typename F> 
    fxn(F&& f) 
     : 
     _holder(new holder<typename std::decay<F>::type>(std::forward<F>(f))) 
    { } 

    R operator() (Args&&... args) 
    { _holder->call(std::forward<Args>(args)...); } 

private: 

    struct holder_base 
    { virtual R call(Args&&... args) = 0; }; 

    template<typename F> 
    struct holder : holder_base 
    { 
     holder(F&& f) : _f(std::forward<F>(f)) { } 
     R call(Args&&... args) { return _f(std::forward<Args>(args)...); } 
     F _f; 
    }; 

    std::unique_ptr<holder_base> _holder; 
}; 

#include <iostream> 

int main() 
{ 
    fxn<void()> f = [] { std::cout << "hello"; }; 
    f(); 
} 
+0

Infatti, molte funzionalità di boost possono essere viste come "pre-standard". – leemes

+0

Bel codice che mostra come possiamo creare questo da zero, ma devi tenere presente che questo è C++ 11. ;) Immagino che l'implementazione del boost sia molto più complicata (suppongo che usino la loro libreria per il preprocessore per quello?) – leemes

+0

@leemes: Sì, certo. Volevo solo fornire una panoramica su ciò che è il principio di implementazione, più o meno. Questo non è solo C++ 11, ma anche molto rudimentale. –