【问题标题】:Why does operator() change for std::function in C++17?为什么 C++17 中 std::function 的 operator() 会发生变化?
【发布时间】:2016-01-09 05:14:16
【问题描述】:

以下代码在 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 段:

返回:如果 R 为 void,则返回 Nothing,否则返回 INVOKE (f, std::forward(args)..., R) 的值。

以上内容已在草稿之间删除。这意味着 lambda 的返回值现在被默默地丢弃。这似乎是一个错误的特征。谁能解释一下原因?

【问题讨论】:

  • LWG 2420。这种行为从一开始就是有意的,只是偶然被删除。
  • @T.C.谢谢。我关注的是库缺陷而不是语言缺陷。
  • 应该是return f(x);
  • @AlanStokes int main() 在 C++ 中可以没有返回值,默认返回 0。另外,f 有返回类型 void 无论如何,不​​能返回。
  • 好吧,我确实说过绑定 :)

标签: c++ c++14 c++17


【解决方案1】:

有一个关于std::function&lt;void(Args...)&gt;ridiculous defect in the standard。根据标准的措辞,std::function&lt;void(Args...)&gt; 的任何(非平凡)1 使用是合法的,因为没有任何东西可以“隐式转换为”void(甚至void)。

void foo() {} std::function&lt;void()&gt; f = foo; 在 C++14 中是不合法的。哎呀。

一些编译器采用了使std::function&lt;void(Args...)&gt; 完全无用的糟糕措辞,并将逻辑仅应用于返回值 void 的传入可调用对象。然后他们得出结论,将返回int 的函数传递给std::function&lt;void(Args...)&gt;(或任何其他非void 类型)是非法的。他们没有把它带到逻辑结束并禁止函数返回voidstd::function 要求对完全匹配的签名没有特殊情况:同样的逻辑适用。)

其他编译器只是忽略了 void 返回类型案例中的错误措辞。

缺陷基本上是调用表达式的返回类型必须可以隐式转换为std::function 签名的返回类型(有关更多详细信息,请参见上面的链接)。而且在标准下,void不能隐式转换为void2

因此缺陷已解决。 std::function&lt;void(Args...)&gt; 现在接受任何可以用Args... 调用的东西,并丢弃返回值,就像许多现有的编译器实现的一样。我认为这是因为 (A) 语言设计者从未有意限制,或者 (B) 需要一种方法让 std::function 丢弃返回值。

std::function 从不要求参数或返回值完全匹配,只是兼容性。如果传入的参数可以从签名参数隐式转换,并且返回类型可以隐式转换为返回类型,那就很高兴了。

在许多直观的定义下,int(int&amp;) 类型的函数与签名 void(int&amp;) 兼容,因为您可以在“无效上下文”中运行它。


1 基本上,任何使operator() 合法调用的东西都是不允许的。你可以创建它,你可以销毁它,你可以测试它(并且知道它是空的)。你不能给它一个函数,即使是一个与它的签名完全匹配的函数,或者一个函数对象或 lambda。可笑。

2 标准下void要隐式转换为void,要求void x = blah;语句有效,其中blah是void类型的表达式;该语句无效,因为您无法创建 void 类型的变量。

【讨论】:

    猜你喜欢
    • 2017-07-25
    • 2020-12-31
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 2019-03-28
    • 1970-01-01
    相关资源
    最近更新 更多