若控制权到达主体的末尾,那个么返回nullopt会破坏什么

What would break if control-reaches-end-of-body were to return nullopt?

本文关键字:返回 nullopt 什么 控制权 主体      更新时间:2023-10-16

C++14为我们提供了自动返回类型推导,C++17有一个optional<T>类型模板(或者类型构造函数,如果你愿意的话)。的确,optional存在于标准库中,而不是语言本身,但是,当控件到达正文末尾时,为什么不将其用作非void函数的返回值呢?我认为:

optional<int> foo(int x)
{
if (x > 0) return 2 * x;
}

应该是分部函数的完全有效且可编译的语法,返回optional<int>

现在,我知道这是一个有点疯狂的想法。我的问题不是你喜欢与否,而是——假设委员会中的每个人都出于某种奇怪的原因真的喜欢它。它会与什么发生冲突?

注意:当然,如果您指定了一个非可选的返回值,这是不起作用的,但这不算作损坏。

想想以abort();结尾的函数或具有相同效果的自定义函数。如果编译器不能静态地证明函数永远不会达到关闭的},这将迫使编译器生成死代码,因此与C++的一个原则相冲突,即零开销原则:不使用什么,就不付费。

特殊套管std::optional在这里很可笑。用户应该能够编写自己的等价于std::optional的一级代码。

这意味着从函数的末尾掉下来需要使用某种魔法来计算隐含的返回值

最简单的魔术是从末端掉下来相当于return {};。在optional的情况下,这就是nullopt。如果我读对了我的标准语,对于int,这是0,这与从-main末尾掉下来的行为相匹配。

也有缺点。首先,假设你有一个函数:

int foo(bool condition) {
if (condition) return 7;
custom_abort(); // does not return, but not marked up with `[[noreturn]]`
}

如果编译器不能证明abort没有返回,这将导致编译器在custom_abort();之后写入return {};。这是有代价的(至少是二进制大小)。目前,编译器可以自由排除abort()之后从foo返回所需的任何工作,假设abort()不会返回。

确实,没有任何有效的程序会因这种变化而表现出不同的行为,但以前未定义的行为会被定义,这可能会带来成本。

我们可以用一种稍微不同的方式来处理这个问题:

int foo(bool condition) {
if (condition) return 7;
custom_abort();
this cannot be reached;
}

我们在C++中添加了一个明确的"无法到达此位置"。

添加后,我们可以对不返回的代码路径发出警告,并在以后的标准中强制执行所有代码路径必须断言它们无法到达或必须返回的规则。

在对语言进行这样的转换一两个标准周期后,那么隐含的return {};将是无害的,除非跳过了标准化的返回阶段。

到目前为止,它是完整的未定义行为。这意味着没有有效的现有代码包含此构造。因此,添加定义良好的行为不会破坏任何有效的代码。至于被破坏的代码,如果你的提议被接受,可能会也可能不会被破坏,但这几乎从来都不是WG21的问题。

主要关注的是它将如何与其他语言功能交互。我认为与constexpr没有冲突;从CCD_ 22函数的末尾脱落将给出空的CCD_。[[noreturn]]属性显然毫无意义。[[nodiscard]]属性影响调用者,而不是实现。例外情况也不受影响。因此,总的来说,这项建议似乎是独立的。

在向WG21提出的建议中,可能值得提出一个不那么激进的替代方案:使普通return;成为return optional<T>{};的有效替代方案