7

我正在阅读boost::function,我对它的使用以及它与我在文档中找到的其他 C++ 结构或术语的关系感到有些困惑,例如这里

boost::function在 C++ (C++11) 的上下文中,实例、函数对象函子lambda 表达式之间有什么区别?什么时候应该使用哪个构造?例如,何时应该将函数对象包装在 a 中boost::function而不是直接使用该对象?

上述所有 C++ 是否都构造了不同的方式来实现函数式语言中称为闭包的内容(一个函数,可能包含捕获的变量,可以作为值传递并由其他函数调用)?

4

3 回答 3

6

函数对象和函子是一回事;实现函数调用运算符的对象operator()。一个 lambda 表达式产生一个函数对象。boost::function具有/的某些特化类型的std::function对象也是函数对象。

Lambda 的特殊之处在于 lambda 表达式具有匿名且唯一的类型,并且是创建内联函子的便捷方式。

boost::function/std::function的特殊之处在于它将任何可调用实体转换为函子,其类型仅取决于可调用实体的签名。例如,每个 lambda 表达式都有一个唯一的类型,因此很难将它们传递给非泛型代码。如果您std::function从 lambda 创建一个,那么您可以轻松地传递包装的 lambda。

于 2012-10-10T14:05:50.133 回答
6

两者boost::function和标准版本std::function都是库提供的包装器。它们可能很昂贵而且很重,只有在您确实需要一异构的、可调用的实体时才应该使用它们。只要您一次只需要一个可调用实体,您最好使用auto或模板。

这是一个例子:

std::vector<std::function<int(int, int)>> v;

v.push_back(some_free_function);           // free function
v.push_back(&Foo::mem_fun, &x, _1, _2);    // member function bound to an object
v.push_back([&](int a, int b) -> int { return a + m[b]; });  // closure

int res = 0;
for (auto & f : v) { res += f(1, 2); }

这是一个反例:

template <typename F>
int apply(F && f)
{
    return std::forward<F>(f)(1, 2);
}

在这种情况下,像这样声明是完全没有理由的apply

int apply(std::function<int(int,int)>)   // wasteful

转换是不必要的,模板版本可以匹配实际(通常是不可知的)类型,例如绑定表达式或 lambda 表达式。

于 2012-10-10T14:22:37.513 回答
3

函数对象和函子通常用一个概念来描述。这意味着它们描述了一种类型的一组需求。在 C++11 中,很多关于 Functor 的东西都发生了变化,新概念被称为Callable. o可调用类型的对象是(基本上)表达式为o(ARGS)真的对象。的例子Callable

int f() {return 23;}

struct FO {
  int operator()() const {return 23;}
};

通常还会添加一些对返回类型的要求Callable。你使用Callable这样的:

template<typename Callable>
int call(Callable c) {
  return c();
}

call(&f);
call(FO());

像上面这样的构造要求您在编译时知道确切的类型。这并不总是可能的,这就是 std::function进来的地方。

std::function是这样的Callable,但它允许您删除您正在调用的实际类型(例如,您接受可调用的函数不再是模板)。仍然调用一个函数需要你知道它的参数和返回类型,因此必须将它们指定为模板参数std::function

你会像这样使用它:

int call(std::function<int()> c) {
  return c();
}

call(&f);
call(FO());

您需要记住,使用std::function会对性能产生影响,并且您应该只在确定需要它时才使用它。在几乎所有其他情况下,模板都可以解决您的问题。

于 2012-10-10T14:25:02.220 回答