2013-02-18 21 views
57

Wiesz, możemy owinąć lub przechowywać funkcję lambda Do std::function:Jak std :: funkcja działa

#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; 
} 

Moje pytanie jest wokół std::function, jak widać jest to klasa szablon ale może zaakceptować każdy rodzaj sygnatury funkcji .

Na przykład float (float, float) w tej formie return_value (first_arg, second_arg).

Jaka jest struktura std::function i jak akceptuje ona sygnaturę funkcji, taką jak x(y,z) i jak z nią działa? Czy float (float, float) nowe prawidłowe wyrażenie w C++?

+7

Wyszukaj typ wymazania w C++. –

+5

Zawsze można otworzyć nagłówek kompilatora '' (uważam, że wszystkie główne kompilatory wysyłają std nagłówki jako kod C++) i sprawdzam je lub zajrzyj do [Boost.Function] (http://www.boost.org/doc /libs/1_53_0/doc/html/function.html). – Angew

+4

@Angew: Tak, bardzo edukacyjne, +1. Myślę, że 'std :: function' dotyka praktycznie każdego aspektu języka C++ ... –

Odpowiedz

93

Używa niektórych type erasure technique.

Jedną z możliwości jest użycie polimorfizmu podtypu mieszanki z szablonami. Oto uproszczona wersja, po prostu dać dotyk dla ogólnej struktury:

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)...); 
    } 
}; 

(Zauważ, że przeoczyłem kilka rzeczy dla uproszczenia: nie może być kopiowany, a może inne problemy, nie korzystać z tego kod w prawdziwym kodzie)

+6

+1. To bardzo godne ubolewania, że ​​nie mogę głosować więcej razy za tę odpowiedź. – xmllmx

+0

@Martinho, gdzie jest definicja "Bez kwalifikacji"? – xmllmx

+2

@xmllmx Jest to szablon aliasów, który usuwa wszystkie kwalifikatory (const, volatile, &, and &&) z typu. Taki sam jak "Bare" tutaj: http://flamingdangerzone.com/cxx11/2012/05/29/type-traits-galore.html#bare_types (od tego czasu zmieniłem zdanie i uznałem, że niewykwalifikowane jest lepsze imię :) –