以下代码在 C++14 中被认为是非法的,但在 C++17 中是合法的:
#include <functional>
int main()
{
int x = 1729;
std::function<void (int&)> f(
[](int& r) { return ++r; });
f(x);
}
不要费心对其进行测试,您会得到不一致的结果,因此很难判断这是错误还是故意行为。然而,比较两个草稿(N4140 与 N4527,两者都可以在 github.com/cplusplus/draft 上找到),[func.wrap.func.inv] 有一个显着差异。第 2 段:
Returns: Nothing if R is void, otherwise the return value of INVOKE (f, std::forward(args)..., R).
以上内容已在草稿之间删除。这意味着 lambda 的返回值现在被默默地丢弃。这似乎是一个错误的特征。谁能解释一下原因?
最佳答案
有一个 ridiculous defect in the standard关于 std::function<void(Args...)>
.根据标准的措辞,没有(非平凡的)1 使用 std::function<void(Args...)>
是合法的,因为没有任何东西可以“隐式转换为”void
(甚至没有 void
)。
void foo() {} std::function<void()> f = foo;
在 C++14 中是不合法的。哎呀。
一些编译器采用了导致 std::function<void(Args...)>
的错误措辞。完全没用,并且仅将逻辑应用于返回值为 not void
的传入可调用对象.然后他们得出结论,传递返回 int
的函数是非法的。至std::function<void(Args...)>
(或任何其他非 void
类型)。他们没有把它带到逻辑结束并禁止返回 void
的函数。以及(std::function
要求对完全匹配的签名没有特殊情况:同样的逻辑适用。)
其他编译器只是忽略了 void
中的错误措辞。返回类型大小写。
缺陷基本上是调用表达式的返回类型必须可以隐式转换为 std::function
的返回类型。的签名(有关详细信息,请参阅上面的链接)。而在标准下,void
不能隐式转换为 void
2.
因此缺陷已解决。 std::function<void(Args...)>
现在接受任何可以用 Args...
调用的东西,并丢弃返回值,正如许多现有编译器实现的那样。我认为这是因为 (A) 语言设计者从未有意限制,或者 (B) 有办法使用 std::function
需要丢弃返回值。
std::function
从不要求参数或返回值完全匹配,只是兼容性。如果传入的参数可以从签名参数隐式转换,并且返回类型可以隐式转换为返回类型,那就很高兴了。
还有一个 int(int&)
类型的函数在许多直观的定义下,与签名 void(int&)
兼容,因为您可以在“无效上下文”中运行它。
1 基本上,任何可以制作 operator()
的东西不允许合法打电话。你可以创建它,你可以销毁它,你可以测试它(并且知道它是空的)。你不能给它一个函数,即使是一个与它的签名完全匹配的函数,或者一个函数对象或 lambda。可笑。
2 对于 void
隐式转换为 void
根据标准,它要求声明void x = blah;
, 其中 blah
是 void 类型的表达式,有效;该语句无效,因为您无法创建 void
类型的变量.
关于c++ - 为什么 C++17 中 std::function 的 operator() 会发生变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33069029/