是否允许 C++ 标准库实现加强 noexcept 规范?
Posted
技术标签:
【中文标题】是否允许 C++ 标准库实现加强 noexcept 规范?【英文标题】:Are C++ standard library implementations allowed to strengthen noexcept specifications? 【发布时间】:2016-06-27 10:05:28 【问题描述】:根据 C++ 标准,C++ 标准库的实现是否允许加强标准定义的 C++ 标准库的方法和其他功能的noexcept
规范?
例如,如果 C++ 标准将某些函数 std::f
指定为 void f();
,是否允许标准库实现将其实现为 void f() noexcept;
?
【问题讨论】:
所有实现在能够证明不会发生异常的情况下都会删除异常处理代码。noexcept
关键字更多地是关于如果调用堆栈中有人对编译器撒谎该怎么办。
@RichardHodges 对我来说,noexcept
只是一个可以在代码中检查的函数契约。 “不抛出”函数的概念一直存在,但现在我们可以在我们的代码中验证它,如果我们想制作一些“异常不安全但更快”的代码。低级代码生成与我几乎无关。
@KABoissonneault 我认为我们在说同样的话 - 你说得比我好:)
【参考方案1】:
标准说是:
§ 17.6.5.12.1 异常处理限制[res.on.exception.handling]
C++ 标准库中定义的任何函数都可以通过抛出其 Throws: 段落中描述的类型的异常来报告失败。实现可以通过添加非抛出noexcept-specification 来加强非虚拟函数的异常规范。
[...]
C++ 标准库中定义的析构函数操作不应引发异常。 C++ 标准库中的每个析构函数都应该表现得好像它有一个非抛出异常规范。任何其他 在 C++ 标准库中定义的没有异常规范的函数可能会抛出实现定义的异常,除非另有说明。实施可能会加强这一点 通过添加显式的异常规范。
(逗号 4 似乎只允许明确说明异常规范,并警告缺少明确的异常规范意味着允许实现抛出任何东西)。
老实说,我不明白为什么允许这样做并且添加 constexpr
是不允许的(第 17.6.5.6 节)。它们看起来像同一块奖牌的两侧——通过使用类型特征和 SFINAE,您可以拥有显示不同行为的代码,具体取决于您使用的标准库实现(如果它将某些函数标记为 noexcept
/constexpr
,或如果没有),这首先违背了制定标准的目的......
【讨论】:
有趣的是,§17.6.5.6 并没有谈到加强具有 constant-expression 的 noexcept-specification。我想知道是不是因为标准没有为标准库指定任何此类内容。 @peppe: "说实话,我不明白为什么这是允许的,而添加 constexpr 是不允许的(第 17.6.5.6 节)。" 意外地依赖于constexpr
而不是noexcept
。在后一种情况下,您必须使用类型特征和/或 SFINAE 来依赖异常规范。在前一种情况下,只需输入constexpr float f = std::sin(32.5f);
。如果编译成功,那么您不小心将您的代码绑定到了实现细节。
@NicolBolas 我要补充一点,与constexpr
不同,在库函数的noexcept
ness 上重载代码并不是完全错误。如果编写得当,您的通用代码仍然是可移植的:它可能只是从一个平台到另一个平台采用不同的代码路径。
@KABoissonneault:简化为最简单的示例:static_assert(noexcept(std::some::function()), "nope")
。我发现 tihs 是否编译取决于实现是有问题的,因为(再次,据我所知)禁止添加 constexpr
背后的原理相同。
注意,他们是originally going to allow this for constexpr以上是关于是否允许 C++ 标准库实现加强 noexcept 规范?的主要内容,如果未能解决你的问题,请参考以下文章
C++ 标准是不是允许在没有开销的情况下实现 std::optional<double>