构造函数在return语句上调用 [英] Constructor called on return statement

查看:177
本文介绍了构造函数在return语句上调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下示例:

class X {
public:
    X() = default;
    X(const X&) = default;
    X(X&&) = delete;
};

X foo() {
    X result;
    return result;
}

int main() {
    foo();
}

Clang和GCC在此程序是否有效上存在分歧.在对foo()的调用期间初始化临时项时,GCC尝试调用move构造函数,该临时项已删除,导致编译错误.即使使用-fno-elide-constructors,Clang也可以很好地处理此问题.

Clang and GCC disagree on whether this program is valid. GCC tries to call the move constructor when initializing the temporary during the call to foo(), which has been deleted leading to a compilation error. Clang handles this just fine, even with -fno-elide-constructors.

有人能解释为什么在这种情况下允许GCC调用move构造函数吗? result不是左值吗?

Can anyone explain why GCC is allowed to call the move constructor in this case? Isn't result an lvalue?

推荐答案

来自 [class.copy.elision] :

在以下复制初始化上下文中,可以使用移动操作代替复制操作:如果return语句中的表达式是(可能带有括号的) id-expression 命名在主体中声明为具有自动存储期限的对象 [...]

In the following copy-initialization contexts, a move operation might be used instead of a copy operation: If the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body [...]

重载分辨率以选择副本的构造函数,就好像该对象是由右值指定的一样. 如果第一个重载解析失败或未执行,或者如果所选构造函数的第一个参数的类型不是对该对象类型的右值引用(可能是cv-合格),则将对象视为左值,再次执行重载解析.

overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.

return result;中,我们恰好在该段提到的情况下-result id-expression 命名的对象,其对象具有在主体中声明的自动存储时间.因此,我们首先执行重载解析,好像它是一个右值.

In return result; we are precisely in the case mentioned in that paragraph - result is an id-expression naming an object with automatic storage duration declared in the body. So, we first perform overload resolution as if it were an rvalue.

重载分辨率将找到两个候选值:X(X const&)X(X&&).首选 .

Overload resolution will find two candidates: X(X const&) and X(X&&). The latter is preferred.

现在,重载解析失败意味着什么?来自 [over.match]/3 :

Now, what does it mean for overload resolution to fail? From [over.match]/3:

如果存在最佳可行的功能并且是唯一的,那么过载解析将成功并产生结果.否则,重载解析将失败并且调用格式错误.

If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed.

X(X&&)是唯一的,最可行的功能,因此重载解析成功 .这个复制省略上下文对我们来说有一个额外的条件,但是我们也满足它,因为该候选项的第一个参数的类型是对X的右值引用(可能是cv限定).两个框均已选中,因此我们在此处停止.我们不再继续作为左值执行重载解析,我们已经选择了候选对象:move构造函数.

X(X&&) is a unique, best viable function, so overload resolution succeeds. This copy elision context has one extra criteria for us, but we satisfy it as well because this candidate has as the type of its first parameter as (possibly cv-qualified) rvalue reference to X. Both boxes are checked, so we stop there. We do not go on to perform overload resolution again as an lvalue, we have already selected our candidate: the move constructor.

一旦选择它,该程序将失败,因为我们正试图调用一个已删除的函数.但是,此时只有 ,而且没有更早的版本.不能从重载集合中排除候选者以进行删除,否则删除重载几乎没有用处.

Once we selected it, the program fails because we're trying to call a deleted function. But only at that point, and not any earlier. Candidates are not excluded from overload sets for being deleted, otherwise deleting overloads wouldn't be nearly as useful.

这是clang错误 31025 .

这篇关于构造函数在return语句上调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆