19

前段时间我用std::function的差不多是这样的:

std::function<void(int)> func = [](int i) -> int { return i; };

基本上,我这样做是因为我想在 a 中存储不同的函数对象std::function,但我不想限制这些函数的返回类型。由于这似乎有效,我就同意了。但我不相信它可以安全使用,我也找不到任何关于它的文档。有谁知道这种用法是否合法?或者更一般地说,可以安全地分配给 a 的对象的规则是什么std::function

编辑

为了澄清起见,我关心的问题是 lambda 函数返回 an int,而func声明为 return type void。我不确定这是否可以,尤其是在拨打电话后func()

4

3 回答 3

21

您的代码具有未定义的行为。它可能会或可能不会按您的预期工作。它具有未定义行为的原因是因为 20.8.11.2.1 [func.wrap.func.con]/p7:

要求: FCopyConstructible。对于参数类型和返回类型f应为 Callable (20.8.11.2) 。ArgTypesR

f对返回类型可调用Rf必须返回可隐式转换为std::function(void在您的情况下) 的返回类型的东西。并且int不能隐式转换为void.

我希望您的代码适用于大多数实现。但是,在至少一种实现(libc++)上,它无法编译:

test.cpp:7:30: error: no viable conversion from 'int (int)' to 'std::function<void (int)>'
    std::function<void(int)> ff = f;
                             ^    ~

具有讽刺意味的是,这种行为的理由源于另一个 SO question

另一个问题提出了std::function使用问题。该问题的解决方案涉及让实现在编译时强制执行Requires:子句。相比之下,这个问题的解决方案是禁止实现强制执行Requires:子句。

于 2012-02-18T17:27:31.550 回答
1

您的用例已根据标准进行了明确定义。

您正在std::function从可调用对象构建 a [1]

§20.8.11.2.1/7:

template<class F> function(F f);

要求:F 应为 CopyConstructible。对于参数类型 ArgTypes 和返回类型 R,f 应为 Callable (20.8.11.2)。

那么你的 f 是可调用的吗?

§20.8.11.2/2 说:

F 类型的可调用对象 f 对于参数类型 ArgTypes 和返回类型 R 来说是可调用的,如果INVOKE (f, declval<ArgTypes>()..., R)被认为是未计算的操作数(第 5 条)的表达式格式正确(20.8.2)。

的定义INVOKE说:

§20.8.2

  1. 定义INVOKE (f, t1, t2, ..., tN)如下: ... 处理成员函数/var 指针的东西 ... —f(t1, t2, ..., tN)在所有其他情况下。

  2. 定义INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN)隐式转换为R.

而且由于任何类型都可以隐式转换为void,因此您的代码应该可以使用符合标准的编译器。正如下面的 litb 所指出的,没有到 void 的隐式转换,所以这没有很好的定义。

[1]:我认为 lambda 在这里算作可调用对象,尽管我对此没有参考。您的 lambda 也可以用作函数指针,因为它不捕获上下文

于 2012-02-18T12:15:47.430 回答
0

这看起来对于匿名函数来说可能没问题。

来自http://www.alorelang.org/release/0.5/doc/std_function.html的引用(这不是来自 C++ 标准库,但看起来他们在绑定到 C++ 时使用了类似的东西)

函数对象只能通过函数定义、匿名函数表达式或使用点 (.) 运算符访问绑定方法来创建。

另一种可能完成的方法是将函数指针存储在 auto 中,如下所示:http ://en.wikipedia.org/wiki/Anonymous_function (C++ 部分)

于 2012-02-18T08:49:39.463 回答