大约的标准有一个荒谬的缺陷std::function<void(Args...)>
。根据标准的措辞,没有(非平凡的)1使用std::function<void(Args...)>
是合法的,因为没有任何东西可以“隐式转换为” void
(甚至不是void
)。
void foo() {} std::function<void()> f = foo;
在 C++14 中是不合法的。哎呀。
一些编译器采用了std::function<void(Args...)>
完全无用的糟糕措辞,并将逻辑仅应用于返回值不是 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&)
,因为您可以在“无效上下文”中运行它。
1operator()
基本上,不允许任何合法的调用。你可以创建它,你可以销毁它,你可以测试它(并且知道它是空的)。你不能给它一个函数,即使是一个与它的签名完全匹配的函数,或者一个函数对象或 lambda。荒谬的。
2为了在标准下void
隐式转换void
,它要求声明void x = blah;
,其中blah
是一个void类型的表达式,是有效的;该语句无效,因为您无法创建 type 的变量void
。