C++ 抛出右旋值

C++ 抛出右旋值,c++,language-lawyer,c++14,throw,C++,Language Lawyer,C++14,Throw,以片段为例: try { Foo f; throw std::move(f); } catch (Foo& f) { } [expr.throw]说: 异常对象的类型 通过从操作数的静态类型中删除任何顶级cv限定符并调整 键入从“T数组”或“返回T的函数”到“指向T的指针”或“指向返回T的函数的指针”, 分别 这将是Foo&。然后根据[except.throw]初始化异常对象: 抛出异常副本会初始化(8.5,12.8)一个临时对象,称为异常对象。这个 temporary

以片段为例:

try {
    Foo f;
    throw std::move(f);
}
catch (Foo& f) { }
[expr.throw]说:

异常对象的类型 通过从操作数的静态类型中删除任何顶级cv限定符并调整 键入从“T数组”或“返回T的函数”到“指向T的指针”或“指向返回T的函数的指针”, 分别

这将是
Foo&
。然后根据[except.throw]初始化异常对象:

抛出异常副本会初始化(8.5,12.8)一个临时对象,称为异常对象。这个 temporary是一个左值,用于初始化匹配处理程序(15.3)中声明的变量。如果 异常对象的类型将是不完整的类型或指向不完整类型的指针,而不是 (可能cv合格)
void
程序格式不正确

这向我建议将exception对象初始化为:

Foo&& __exception_object = std::move(f);

而且处理程序不匹配。然而,gcc和clang都捕获了这个异常。那么,这里异常对象的实际类型是什么?如果
Foo
,为什么?

表达式的静态类型永远不是引用类型

1.3.24[定义静态类型]定义了“静态类型”:

在不考虑执行语义的情况下,通过分析程序得到的表达式类型(3.9)

“程序分析”的第一步是删除引用,请参阅 5[expr]p5和

如果表达式最初具有类型“reference to
T
”(8.3.2,8.5.3),则在进行任何进一步分析之前,该类型将调整为
T
。表达式指定由引用表示的对象或函数,表达式是左值或x值,具体取决于表达式

因此,
std::move(f)
是一个xvalue表达式,具有静态类型
Foo

您不需要使用右值来演示这一点,C++03中的情况也是如此:

int& f();
throw f();
这会抛出一个
int
而不是
int&

在不考虑细节的情况下,异常对象是对象,而引用不是对象,因此异常对象不能是引用。它一定是个物体