std :: function如何工作


69

您知道,我们可以将lambda函数包装或存储到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 ++中是否有新的有效表达式?


8
在C ++中查找类型擦除。
R. Martinho Fernandes

5
您总是可以打开编译器的<function>标头(我相信所有主要的编译器都将std标头作为C ++代码提供)并进行检查,或者查看Boost.Function
Angew不再为SO

4
@Angew:是的,很有教育意义,+ 1。我认为std::function几乎涉及C ++语言的各个方面……
Kerrek SB

为了更轻松地进行心理锻炼,请尝试了解其std::bind工作原理...
Kerrek SB 2013年

Answers:


115

它使用某种类型的擦除技术

一种可能性是使用带有模板的混合亚型多态性。这是一个简化的版本,只是为了让您了解整体结构:

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

(请注意,为简单起见,我忽略了几件事:无法复制它,可能还有其他问题;请勿在实际代码中使用此代码)


7
+1。非常遗憾的是,我无法为该答案增加投票时间。
xmllmx

@Martinho,“不合格”的定义在哪里?
xmllmx

2
@xmllmx这是一个别名模板,用于删除类型中的所有限定符(const,volatile,&和&&)。与Bare此处相同:flamingdangerzone.com/cxx11/2012/05/29/…(此后我改变了主意,发现不合格的名字更好:)
R. Martinho Fernandes

2
@xmllmx,实际上,可以解决这个问题。它应该std::decay改为(它模拟值传递语义,这就是我想要的:我想按值存储)。它们相似,但在这里并不完全相同。
R. Martinho Fernandes

@ Martinho,function :: operator()中缺少参数名称“ args”。请添加它以使代码完整。
xmllmx
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.