2013-03-10 8 views
12

La notazione per la funzione std :: è piuttosto piacevole se confrontata con i puntatori di funzione. Tuttavia, a parte questo, non riesco a trovare un caso d'uso in cui non possa essere sostituito da puntatori. Quindi è solo zucchero sintattico per i puntatori di funzione?Esiste un caso d'uso per la funzione std :: che non è coperta dai puntatori di funzione, o è solo zucchero sintattico?

+4

Qualsiasi oggetto callable che non è una funzione? Funtori dichiarati, lambda, espressioni vincolanti ...? –

+1

std :: function è zucchero sintattico per tutti i tipi di funtori, non solo per i puntatori di funzione. – nurettin

+2

@Xeo: le risposte in questa domanda sono molto meglio. –

risposta

24

std::function<> ti dà la possibilità di incapsulare qualsiasi tipo di oggetto callable, che è qualcosa di puntatori a funzione non possono farlo (anche se è vero che non catturare lambda possono essere convertiti per funzionare puntatori).

Per dare un'idea del tipo di flessibilità che consente di ottenere:

#include <functional> 
#include <iostream> 
#include <vector> 

// A functor... (could even have state!) 
struct X 
{ 
    void operator()() { std::cout << "Functor!" << std::endl; } 
}; 

// A regular function... 
void bar() 
{ 
    std::cout << "Function" << std::endl; 
} 

// A regular function with one argument that will be bound... 
void foo(int x) 
{ 
    std::cout << "Bound Function " << x << "!" << std::endl; 
} 

int main() 
{ 
    // Heterogenous collection of callable objects 
    std::vector<std::function<void()>> functions; 

    // Fill in the container... 
    functions.push_back(X()); 
    functions.push_back(bar); 
    functions.push_back(std::bind(foo, 42)); 

    // And a add a lambda defined in-place as well... 
    functions.push_back([]() { std::cout << "Lambda!" << std::endl; }); 

    // Now call them all! 
    for (auto& f : functions) 
    { 
     f(); // Same interface for all kinds of callable object... 
    } 
} 

Come al solito, vedere un live example here. Tra le altre cose, questo ti permette di realizzare lo Command Pattern.

+0

Grazie mille, il tuo esempio ha molto senso. –

+0

@static_rtti: OK, felice che abbia aiutato :) –

+0

perché sei così poco entusiasta delle funzioni regolari? (è l'unico mancante '!') :-P –

7

std::function è progettato per rappresentare qualsiasi tipo di oggetto callable. Ci sono molti oggetti chiamabili che non possono essere rappresentati in alcun modo da un puntatore a funzione.

  1. un funtore:

    struct foo { 
        bool operator()(int x) { return x > 5; } 
    }; 
    
    bool (*f1)(int) = foo(); // Error 
    std::function<bool(int)> f2 = foo(); // Okay 
    

    Non è possibile creare un'istanza di foo e conservarlo in un puntatore a funzione di bool(*)(int).

  2. Un lambda con una lambda-capture:

    bool (*f1)(int) = [&](int x) { return x > y; }; // Error 
    std::function<bool(int)> f2 = [&](int x) { return x > y; }; // Okay 
    

    Tuttavia, un lambda senza cattura può essere convertito in un puntatore alla funzione:

    Il tipo di chiusura per un lambdacia- l'espressione senza lambda-capture ha una funzione di conversione const non-public pubblica non virtuale per puntare a una funzione che ha lo stesso parametro e tipi di ritorno dell'operatore di chiamata di funzione del tipo di chiusura. Il valore restituito da questa funzione di conversione deve essere l'indirizzo di una funzione che, invocata, ha lo stesso effetto del richiamo dell'operatore di chiamata di funzione del tipo di chiusura.

  3. implementazione definita valori restituiti callable:

    bool foo(int x, int y) { return x > y; }; 
    
    bool (*f1)(int) = std::bind(&foo, std::placeholders::_1, 5); // Error (probably) 
    std::function<bool(int)> f2 = std::bind(&foo, std::placeholders::_1, 5); // Okay 
    

    s' std::bind valore restituito è un oggetto richiamabile definito dall'implementazione. Solo come può essere usato quell'oggetto è specificato dallo standard, non dal suo tipo.

Problemi correlati