2013-02-18 11 views
57

Sai, siamo in grado di avvolgere o conservare una funzione lambda ad un std::function:Come std :: funzione opera

#include <iostream> 
#include <functional> 
int main() 
{ 
    std::function<float (float, float)> add = [](float a, float b) 
    //   ^^^^^^^^^^^^^^^^^^^^ 
    { 
     return a + b; 
    }; 

    std::cout << add(1, 2) << std::endl; 
} 

La mia domanda è di circa std::function, come potete vedere si tratta di un modello di classe, ma può accettare qualsiasi tipo di firma di funzione .

Ad esempio float (float, float) in questo formato return_value (first_arg, second_arg).

Qual è la struttura di std::function e come accetta una firma di funzione come x(y,z) e come funziona? float (float, float) una nuova espressione valida in C++?

+7

Cerca cancellazione di tipo in C++. –

+5

Puoi sempre aprire l'intestazione '' del compilatore (credo che tutti i principali compilatori inviino intestazioni standard come codice C++) e ispezionarlo, o dare un'occhiata a [Boost.Function] (http://www.boost.org/doc /libs/1_53_0/doc/html/function.html). – Angew

+4

@Angew: Sì, molto istruttivo, +1. Penso che 'std :: function' tocchi praticamente ogni aspetto del linguaggio C++ ... –

risposta

93

Utilizza alcuni type erasure technique.

Una possibilità è utilizzare il polimorfismo del sottotipo di mix con i modelli. Ecco una versione semplificata, giusto per dare un tatto per la struttura generale:

template <typename T> 
struct function; 

template <typename Result, typename... Args> 
struct function<Result(Args...)> { 
private: 
    // this is the bit that will erase the actual type 
    struct concept { 
     virtual Result operator()(Args...) const = 0; 
    }; 

    // this template provides us derived classes from `concept` 
    // that can store and invoke op() for any type 
    template <typename T> 
    struct model : concept { 
     template <typename U> 
     model(U&& u) : t(std::forward<U>(u)) {} 

     Result operator()(Args... a) const override { 
      t(std::forward<Args>(a)...); 
     } 

     T t; 
    }; 

    // this is the actual storage 
    // note how the `model<?>` type is not used here  
    std::unique_ptr<concept> fn; 

public: 
    // construct a `model<T>`, but store it as a pointer to `concept` 
    // this is where the erasure "happens" 
    template <typename T, 
     typename=typename std::enable_if< 
      std::is_convertible< 
       decltype(t(std::declval<Args>()...)), 
       Result 
      >::value 
     >::type> 
    function(T&& t) 
    : fn(new model<typename std::decay<T>::type>(std::forward<T>(t))) {} 

    // do the virtual call  
    Result operator()(Args... args) const { 
     return (*fn)(std::forward<Args>(args)...); 
    } 
}; 

(Si noti che ho trascurato diverse cose per il gusto della semplicità: non può essere copiato, e forse altri problemi, non utilizzare questo codice in codice reale)

+6

+1. È altamente deplorevole che non riesca a mandarmi più volte per questa risposta. – xmllmx

+0

@Martinho, dov'è la definizione di "Non qualificato"? – xmllmx

+2

@xmllmx È un modello alias che rimuove tutti i qualificatori (const, volatile, &, and &&) da un tipo. Lo stesso di 'Bare' qui: http://flamingdangerzone.com/cxx11/2012/05/29/type-traits-galore.html#bare_types (Ho cambiato idea e ho trovato Unqualified come migliore) :) –

Problemi correlati