【问题标题】:How will C++17 exception specifier type system work?C++17 异常说明符类型系统将如何工作?
【发布时间】:2016-12-10 04:33:26
【问题描述】:

研究“noexcept 说明符(和运算符)”,我写了一个简单的代码。我很惊讶这段代码:

void asdf() noexcept {}
int main() 
{
    auto f = asdf;
    std::cout << std::boolalpha << noexcept(f()) << std::endl;
}

打印false,甚至函数“asdf”也没有指定。

所以在寻找为什么会发生这种神秘现象的过程中,我发现了 C++17 的“异常说明符类型系统”——P0012R1

根据这个(接受的)提案,从 C++17 开始;因为noexcept是函数类型的一部分,上面的代码会打印true吗?

还有一个,在this问题的一行:

std::function<void() noexcept> f

noexcept 指定在 C++14 或 11 中似乎被忽略了。 这段代码会在 C++17 中按预期工作吗?

【问题讨论】:

  • g++ return true for noexcept(f()) without -std=c++1z(但 clang 确实返回 false)。
  • 为了获得更多乐趣,请将auto f = asdf; 更改为void(*f)() noexcept = asdf;。现在 GCC 打印 false 而 clang 打印 true
  • @Holt 感谢您提供信息。我正在使用 MSVC(返回 false)。他们会有什么不同?这是 g++ 或 C++14 或更早标准的错误,没有指定 noexcept 类型系统?
  • @hvd 对于该代码,MSVC 打印 true。我现在很困惑:p
  • @hvd 使用函数指针版本,如果你去掉asdf上的noexcept,clang会拒绝做作但gcc不会抱怨...我猜gcc忽略noexcept函数指针声明。

标签: c++ c++11 c++14 c++17 noexcept


【解决方案1】:

根据这个(接受的)提案,从 C++17 开始;由于 noexcept 是函数类型的一部分,上面的代码会打印true吗?

是的。

f 的类型将被推导出为void(*)() noexcept,因为应用于asdf 的函数到指针的转换将保留noexcept 属性。对 noexcept 函数指针的调用肯定不会引发异常,除非它的子表达式之一这样做。

有关确切措辞,请参阅[expr.unary.noexcept]/3[expect.spec]/13。请注意,C++17 草案后一段中的新措辞来自 P0012R1,在 OP 中链接。

如果表达式 ([except.spec]) 的潜在异常集合为空,则 noexcept 运算符的结果为 true,否则为 false

...

  • 如果e 是一个函数调用([expr.call]):
    • 如果它的 postfix-expression 是(可能带括号的)id-expression ([expr.prim.id]),则类成员访问 ([expr.ref] ),或指向成员的操作 ([expr.mptr.oper]),其 cast-expressionid-expression, S是由包含的id-expression 选择的实体的异常规范中的类型集(在重载决议之后,如果适用)。 ...

所以f() 的潜在异常集合与f 的异常规范中的类型集合相同,因为f 被声明为noexcept,所以它是空的。

让我们继续第二个问题:

noexcept 指定在 C++14 或 11 中似乎被忽略了。这段代码在 C++17 中是否能按预期工作?

您的问题似乎是:std::function&lt;void() noexcept&gt; 会拒绝持有一个可以抛出异常的函数吗?

我会说它不清楚。在标准的当前措辞中,std::function&lt;void() noexcept&gt; 实际上并没有定义,就像std::function&lt;double(float) const&gt; is not defined 一样。这在 C++14 中当然不是问题,因为 noexcept 不被视为函数类型的一部分。

std::function&lt;void() noexcept&gt; 会简单地破坏 C++17 吗?这对我来说是不确定的。让我们看一下当前的措辞,以猜测行为“应该”是什么。

标准要求std::function&lt;R(ArgTypes..)&gt; 的构造函数的参数对于参数类型ArgTypes... 和返回类型R 是“Lvalue-Callable”,其中means

可调用类型 ([func.def]) F 对于参数类型 ArgTypes 和返回类型 RLvalue-Callable 如果表达式 INVOKE(declval&lt;F&amp;&gt;(), declval&lt;ArgTypes&gt;()..., R) 被视为未评估操作数(子句 [expr]),格式正确([func.require])。

也许应该有一个额外的要求,如果函数类型是noexcept,那么noexcept(INVOKE(...))也必须为真。尽管如此,目前的草案中并没有这种措辞。

在 P0012R1 中有一条注释:

如何通过std::function 传播“noexcept”是一个悬而未决的问题。

我的猜测是,他们的意思是,如果施加此附加要求,尚不清楚如何实施 std::function。希望其他人可以提供更多详细信息。

【讨论】:

  • 显然我们需要std::function_moveonlystd::function_noexceptonlystd::function_moveonly_noexceptonly。但是std::function_mutablecall 呢?这可能会变得一团糟。
  • 只是评论看看人们是否对此有更多最新的观察,而不提出新问题
猜你喜欢
  • 1970-01-01
  • 2022-10-20
  • 1970-01-01
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
相关资源
最近更新 更多