12

与函数指针相比​​,std::function 的符号非常好。但是,除此之外,我找不到不能用指针替换它的用例。那么它只是函数指针的语法糖吗?

4

2 回答 2

26

std::function<>为您提供了封装任何类型的可调用对象的可能性,这是函数指针无法做到的(尽管确实可以将非捕获lambda 转换为函数指针)。

为了让您了解它允许您实现的灵活性:

#include <functional>
#include <iostream>
#include <vector>

// A functor... (could even have state!)
struct X
{
    void operator () () { std::cout << "Functor!" << std::endl; }
};

// A regular function...
void bar()
{
    std::cout << "Function" << std::endl;
}

// A regular function with one argument that will be bound...
void foo(int x)
{
    std::cout << "Bound Function " << x << "!" << std::endl;
}

int main()
{
    // Heterogenous collection of callable objects
    std::vector<std::function<void()>> functions;

    // Fill in the container...
    functions.push_back(X());
    functions.push_back(bar);
    functions.push_back(std::bind(foo, 42));

    // And a add a lambda defined in-place as well...
    functions.push_back([] () { std::cout << "Lambda!" << std::endl; });

    // Now call them all!
    for (auto& f : functions)
    {
        f(); // Same interface for all kinds of callable object...
    }
}

像往常一样,在这里看一个活生生的例子。除其他外,这使您可以实现命令模式

于 2013-03-10T12:18:45.890 回答
8

std::function旨在表示任何类型的可调用对象。有很多可调用对象不能用函数指针以任何方式表示。

  1. 一个函子:

    struct foo {
      bool operator()(int x) { return x > 5; }
    };
    
    bool (*f1)(int) = foo(); // Error
    std::function<bool(int)> f2 = foo(); // Okay
    

    您不能创建实例foo并将其存储在bool(*)(int)函数指针中。

  2. 带有lambda-capture的 lambda :

    bool (*f1)(int) = [&](int x) { return x > y; }; // Error
    std::function<bool(int)> f2 = [&](int x) { return x > y; }; // Okay
    

    但是,没有捕获的 lambda 可以转换为函数指针:

    没有 lambda-capture 的 lambda 表达式的闭包类型具有一个公共的非虚拟非显式 const 转换函数,该函数指向具有与闭包类型的函数调用运算符相同的参数和返回类型的函数的指针。这个转换函数返回的值应该是一个函数的地址,当被调用时,它与调用闭包类型的函数调用运算符具有相同的效果。

  3. 实现定义的可调用返回值:

    bool foo(int x, int y) { return x > y; };
    
    bool (*f1)(int) = std::bind(&foo, std::placeholders::_1, 5); // Error (probably)
    std::function<bool(int)> f2 = std::bind(&foo, std::placeholders::_1, 5); // Okay
    

    std::bind的返回值是实现定义的可调用对象。标准仅指定如何使用该对象,而不是其类型。

于 2013-03-10T12:23:16.010 回答