调用左值引用构造函数而不是右值引用构造函数 [英] Lvalue reference constructor is called instead of rvalue reference constructor
问题描述
有此代码:
#include <iostream>
class F {
public:
F() = default;
F(F&&) {
std::cout << "F(F&&)" << std::endl;
}
F(F&) {
std::cout << "F(F&)" << std::endl;
}
};
class G {
F f_;
public:
G(F&& f) : f_(f) {
std::cout << "G()" << std::endl;
}
};
int main(){
G g = F();
return 0;
}
输出为:
F(F&)
G()
为什么在类G
的构造函数中调用F(F&)
构造函数而不是F(F&&)
构造函数?类G
的构造函数的参数是F&& f
,它是右值引用,但调用了左值引用的构造函数.
Why F(F&)
constructor is called instead of F(F&&)
constructor in constructor of class G
? The parameter for constructor of class G
is F&& f
which is rvalue reference but constructor for lvalue reference is called.
推荐答案
为什么在类G的构造函数中调用F(F&)构造函数而不是F(F&&)构造函数?
Why F(F&) constructor is called instead of F(F&&) constructor in constructor of class G?
因为f
是左值.即使它与右值绑定,并且其类型是对F
的右值引用,它还是一个命名变量.这使其成为左值.不要忘记对象的值类别不是由其类型决定的,反之亦然.
Because f
is an lvalue. Even though it is bound to an rvalue, and its type is rvalue reference to F
, it is also a named variable. That makes it an lvalue. Don't forget that the value category of an object is not determined by its type, and vice versa.
将左值传递给函数时,只能将左值引用绑定到该函数.如果只想捕获右值,则应按以下方式更改代码:
When you pass an lvalue to a function, only lvalue references can be bound to it. You should change your code as follows if you want to catch rvalues only:
class G {
F f_;
public:
G(F&& f) : f_(std::move(f)) {
std::cout << "G()" << std::endl;
}
};
或者,您可以使用std::forward<>()
,在这种情况下,它是等效的,但是可以使转发 f
的意图更加明确:
Alternatively, you could use std::forward<>()
, which is equivalent in this case, but makes your intent of forwarding f
even clearer:
class G {
F f_;
public:
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
};
现在,最后一个定义易于扩展,因此类型为F
的左值和右值都可以绑定到参数f
:
Now this last definition is easy to extend so that both lvalues and rvalues of type F
can be bound to the parameter f
:
class G {
F f_;
public:
template<typename F>
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
};
例如,这允许通过以下方式构造G
的实例:
This allows, for instance, to construct an instance of G
this way:
F f;
G g(f); // Would not be possible with a constructor accepting only rvalues
最后一个版本具有 caveat :您的构造函数 基本上也将用作复制构造器 ,因此您可能希望显式定义所有可能的复制构造器,以免出现尴尬的情况:
This last version has a caveat though: your constructor will basically work as a copy-constructor as well, so you might want to explicitly define all the possible copy constructors to avoid awkward situations:
class G {
F f_;
public:
template<typename F>
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
G(G const&) = default;
G(G&); // Must be defaulted out-of-class because of the reference to non-const
};
G::G(G&) = default;
由于非模板函数优先于函数模板的实例化,因此在从另一个G
对象构造G
对象时,将选择复制构造函数.当然, move 构造函数也是如此.这留作练习.
Since non-template functions are preferred over instantiations of function templates, the copy constructor will be selected when constructing a G
object from another G
object. The same applies, of course, to the move constructor. This is left as an exercise.
这篇关于调用左值引用构造函数而不是右值引用构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!