2013-02-18 9 views
57

は、我々はラムダ関数をラップするか、保存することができますどのように動作するのstd :: std::function機能は、あなたが知っている

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

私の質問は、あなたがそれをテンプレートクラスで見ることができますが、それが受け入れることができるように、周りのstd::functionです任意の種類の機能の署名

たとえば、この形式のfloat (float, float)は、return_value (first_arg, second_arg)です。

std::functionの構造は何ですか?また、x(y,z)のような機能の署名をどのように受け入れ、どのように機能するのですか? float (float, float)はC++の新しい有効な式ですか?

+7

C++でタイプイレージャをルックアップします。 –

+5

コンパイラの ''ヘッダをいつでも開くことができます(私はすべての主要コンパイラが標準ヘッダをC++コードとして提供していると思います)、それを調べたり、[Boost.Function](http://www.boost.org/doc /libs/1_53_0/doc/html/function.html)。 – Angew

+4

@Angew:はい、とても教育的です。私は 'std :: function'がC++言語のあらゆる面に触れていると思います... –

答えて

93

type erasure techniqueを使用しています。

1つの可能性は、テンプレートとミックスサブタイプ多型を使用することです。ここでは単純化されたバージョンは、単に全体的な構造のための感じを与えるために、です:

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

(私は簡単にするためにいくつかのことを見落としていることに注意してください:それはコピーすることはできません、そしておそらく他の問題、これを使用しないでくださいコードを実際のコードで)

+6

+1。私はこの答えのためにもっと時間をupvoteできないことは非常に残念です。 – xmllmx

+0

@Martinho、 'Unqualified'の定義はどこですか? – xmllmx

+2

@xmllmxタイプからすべての修飾子(const、volatile、&、&&)を削除するエイリアステンプレートです。 http://flamingdangerzone.com/cxx11/2012/05/29/type-traits-galore.html#bare_types(以来私は心が変わり、Unqualifiedがより良い名前になっています:) –

関連する問題