[英]Why does operator() change for std::function in C++17?
以下代码在C ++ 14中被认为是非法的,但在C ++ 17中是合法的:
#include <functional>
int main()
{
int x = 1729;
std::function<void (int&)> f(
[](int& r) { return ++r; });
f(x);
}
不要费心去测试它,你会得到不一致的结果,因此难以判断它是一个bug还是故意的行为。 但是,比较两个草稿(N4140和N4527,两者都可以在github.com/cplusplus/draft上找到),[func.wrap.func.inv]有一个显着的区别。 第2段:
返回:如果R为空则无效,否则返回值为INVOKE(f,std :: forward(args)...,R)。
在草稿之间删除了上述内容。 这意味着lambda的返回值现在被静默丢弃 。 这似乎是一种错误。 任何人都可以解释这个推理吗?
关于std::function<void(Args...)>
的标准中存在一个荒谬的缺陷 。 根据标准的措辞,没有(非平凡) 1使用std::function<void(Args...)>
是合法的,因为没有任何东西可以“隐式转换为” void
(甚至void
)。
void foo() {} std::function<void()> f = foo;
在C ++ 14中不合法。 哎呀。
有些编译器采用了错误的措辞,使得std::function<void(Args...)>
完全无用,并且仅将逻辑应用于传入的callables,其中返回值不为 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&)
兼容,因为您可以在“void context”中运行它。
1基本上,不允许任何使operator()
合法调用的东西。 你可以创建它,你可以销毁它,你可以测试它(并知道它是空的)。 你不能给它一个函数,即使是一个与其签名完全匹配的函数,或函数对象或lambda。 荒谬。
2对于void
被impliclty转换成void
的标准下,它要求的语句void x = blah;
,其中blah
是void类型的表达式,是有效的; 该语句无效,因为您无法创建void
类型的变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.