为什么在类G的构造函数中调用F(F&)构造函数而不是F(F&&)构造函数?
Because f
是一个左值。尽管它是bound到一个右值,其类型是对的右值引用F
,它也是一个命名变量。这使它成为左值。别忘了对象的值类别并不由其类型决定,反之亦然。
当您将左值传递给函数时,只有左值引用可以绑定到它。如果您只想捕获右值,您应该按如下方式更改代码:
class G {
F f_;
public:
G(F&& f) : f_(std::move(f)) {
std::cout << "G()" << std::endl;
}
};
或者,您可以使用std::forward<>()
,在本例中是等效的,但使您的意图转发 f
更清楚:
class G {
F f_;
public:
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
};
现在,最后一个定义很容易扩展,以便类型的左值和右值F
可以绑定到参数f
:
class G {
F f_;
public:
template<typename F>
G(F&& f) : f_(std::forward<F>(f)) {
std::cout << "G()" << std::endl;
}
};
例如,这允许构造一个实例G
这边走:
F f;
G g(f); // Would not be possible with a constructor accepting only rvalues
最后一个版本有一个caveat不过:你的构造函数基本上也可以作为复制构造函数 https://web.archive.org/web/20141205121901/http://flamingdangerzone.com:80/cxx11/2012/06/05/is_related.html,因此您可能需要显式定义所有可能的复制构造函数以避免尴尬的情况:
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构造函数。这留作练习。