使用`std :: function <void(...)>`来调用非空函数</void(...)>

时间:2012-02-18 08:37:44

标签: c++ c++11 return-type std-function

前段时间我使用std::function非常像这样:

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

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

修改

为了澄清,我关心的问题是lambda函数返回int,而func声明返回类型void。我不确定这是否正常,特别是在拨打func()之后。

3 个答案:

答案 0 :(得分:20)

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

  

要求: F应为CopyConstructiblef对于参数类型ArgTypes应为Callable(20.8.11.2)并返回类型R

要使f为可返回类型R可调用,f必须返回隐式可转换为std::functionvoid的返回类型的内容案件)。并且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;
                             ^    ~

具有讽刺意味的是,这种行为的基本原理来自another SO question

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

答案 1 :(得分:1)

您的用例根据标准明确定义。

您正在从可调用对象[1]

构建std::function

§20.8.11.2.1/ 7:

template<class F> function(F f);
     

要求:F应为CopyConstructible。对于参数类型ArgTypes,f应为Callable(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指针的东西......    - 在所有其他情况下f(t1, t2, ..., tN)

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

  4.   

由于任何类型都可以隐式转换为void,因此您的代码应该适合符合标准的编译器。正如下面的litb所指出的,没有隐含的转换为void所以这个定义不明确。

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

答案 2 :(得分:0)

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

来自http://www.alorelang.org/release/0.5/doc/std_function.html的引用(这不是来自C ++标准库,但看起来它们使用类似于绑定到C ++的类似内容)

  

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

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