2013-02-18 120 views
57

你知道,我们可以包装或存放lambda函数的std::function怎样的std ::功能工作

#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++中查找类型擦除。 – 2013-02-18 12:50:26

+5

你可以随时打开你的编译器的''头文件(我相信所有的主要编译器都会将std头文件作为C++代码)并检查它,或者查看[Boost.Function](http://www.boost.org/doc) /libs/1_53_0/doc/html/function.html)。 – Angew 2013-02-18 12:52:00

+4

@Angew:是的,很有教育意义,+1。我认为'std :: function'涉及到C++语言的各个方面...... – 2013-02-18 12:54:36

回答

93

它使用一些type erasure technique

一种可能性是将混合亚型多态性与模板结合使用。下面是一个简化版本,只给一个感觉为整体结构:

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。非常遗憾,我无法为这个答案争取更多的时间。 – xmllmx 2013-02-18 14:44:33

+0

@Martinho,'不合格'的定义在哪里? – xmllmx 2013-02-18 14:52:23

+2

@xmllmx它是一个别名模板,用于从类型中删除所有限定符(const,volatile,&和&&)。与此处的“裸”相同:http://flamingdangerzone.com/cxx11/2012/05/29/type-traits-galore.html#bare_types(我已经改变了主意,发现不合格是一个更好的名字:) – 2013-02-18 14:56:05