前段时间我使用std::function
非常像这样:
std::function<void(int)> func = [](int i) -> int { return i; };
基本上,我这样做是因为我想在std::function
中存储不同的函数对象,但我不想限制这些函数的返回类型。由于这似乎有效,我接受了它。但我不相信它是安全的,我也无法找到任何文件。有谁知道这种用法是否合法?或者更一般地说,对象的规则是什么,可以安全地分配给std::function
?
为了澄清,我关心的问题是lambda函数返回int
,而func
声明返回类型void
。我不确定这是否正常,特别是在拨打func()
之后。
答案 0 :(得分:20)
您的代码有未定义的行为。它可能会或可能不会像您期望的那样工作。它有未定义行为的原因是因为20.8.11.2.1 [func.wrap.func.con] / p7:
要求:
F
应为CopyConstructible
。f
对于参数类型ArgTypes
应为Callable(20.8.11.2)并返回类型R
。
要使f
为可返回类型R
可调用,f
必须返回隐式可转换为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;
^ ~
具有讽刺意味的是,这种行为的基本原理来自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
定义
INVOKE (f, t1, t2, ..., tN)
如下: ...处理成员函数/ var指针的东西...... - 在所有其他情况下f(t1, t2, ..., tN)
。- 醇>
定义
INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN)
隐式转换为R
。
由于任何类型都可以隐式转换为正如下面的litb所指出的,没有隐含的转换为void所以这个定义不明确。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)