使用 'std::function<void(...)>' 调用 non-void 函数

Using `std::function<void(...)>` to call non-void function

本文关键字:调用 gt 函数 non-void lt std function 使用 void      更新时间:2023-10-16

不久前,我使用的std::function非常像这样:

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

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

编辑

为了澄清,我关心的问题是lambda函数返回一个int,而func是用返回类型void声明的。我不确定这是否可以,尤其是在呼叫func()之后。

您的代码有未定义的行为。它可能如你所期望的那样起作用,也可能不起作用。它具有未定义行为的原因是20.8.11.2.1[func.wrap.func.con]/p7:

要求:F应为CopyConstructible。对于参数类型ArgTypes和返回类型Rf应为可调用(20.8.11.2)。

对于返回类型Rf是可调用的,f必须返回一些隐式可转换为std::function的返回类型的内容(在您的情况下为void)。并且CCD_ 18不能隐式地转换为CCD_。

我希望您的代码能够用于大多数实现。然而,在至少一个实现(libc++)上,它无法编译:

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

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

另一个问题是std::function的使用问题。该问题的解决方案包括让实现在编译时强制执行Requires:子句。相反,这个问题的解决方案是禁止实现强制执行Requires:子句。

您的用例是根据标准定义的

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

§20.8.11.2.1/7:

template<class F> function(F f);

要求:F应为可复制结构。对于参数类型ArgTypes,f应为可调用的(20.8.11.2)和返回类型R。

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

§20.8.11.2/2规定:

类型为f的可调用对象f对于参数类型ArgTypes是可调用的如果表达式INVOKE (f, declval<ArgTypes>()..., R)被视为未赋值的操作数,则返回类型R(第5条),形成良好(20.8.2)

INVOKE的定义是:

§20.8.2

  1. INVOKE (f, t1, t2, ..., tN)的定义如下:…处理成员函数/var指针的东西。。。--CCD_ 25。

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

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

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

这看起来可能适用于匿名函数。

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

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

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