prvalue省略在抛出表达式中是否被允许?

6
在C++标准的§[except.throw]中,规定抛出异常会从throw表达式中复制初始化异常对象。
引用如下: > 抛出异常会复制初始化(11.6, 15.8)一个临时对象,称为异常对象。
那么,为什么以下代码在C++17上可以编译通过呢?
class Exception {
public:
   Exception() = default;
   Exception(Exception&&) = delete;
   Exception(const Exception&) = delete;
};

int main() {
    throw Exception{};
    return 0;
}

(https://wandbox.org/permlink/R3WfzfnBAORTLVSy)

复制初始化不包括任何符合prvalue省略条件的情况(至少在我看来是这样)。为什么上述代码在C++17中可以编译通过呢?


2
你是否对为什么没有使用复制构造函数感到困惑?你是否混淆了复制初始化和复制构造? - xaxxon
1个回答

8
从最近的草案标准中(点击这里),我们可以了解到以下内容:
11.6 [dcl.init]/15
通过花括号或等号初始化(9.4),参数传递,函数返回,抛出异常(18.1),异常处理(18.3)和聚合体成员初始化(11.6.1)所进行的初始化称为复制初始化。
因此 T x = T(); 是复制初始化的一个例子,抛出异常和许多其他情况也是复制初始化。
复制初始化的定义在11.6的其他部分中。与prvalues在初始化器中的相关部分如下:
11.6 [dcl.init]/17.6.1
如果初始化表达式是prvalue,且源类型的cv-unqualified版本与目标类相同,则使用初始化表达式来初始化目标对象。
这也被称为保证省略。如果初始化表达式是匹配类型的prvalue表达式,则使用该prvalue表达式直接构造初始化的目标。

@Curious 从标准草案中提取了两个引用,而不是从编辑标准的建议中提取引用。 - Yakk - Adam Nevraumont
1
@Curious 第一句话说抛出异常使用复制初始化。第二句话说初始化表达式初始化目标对象。因此,Exception{}初始化了对象。我认为这并不是真正的省略。 - xaxxon
等等,不对,{} 不是一个表达式。嗯。 - aschepler
@aschepler Exception{} 是一个类型为 Exception 的 prvalue 表达式。当你使用它来进行复制初始化时,它将直接从 prvalue 表达式构造。 - Yakk - Adam Nevraumont
2
啊哈。函数式转换和static_cast(有时是C风格转换)中的[expr]子句中的细节指定,如果表达式是用于初始化结果对象的类prvalue,则在表达式中的初始化程序或操作数用于初始化该结果对象,并且这些规则可以递归应用。 - aschepler
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接