唯一要回答的问题是为什么T&
导致T&
而不是T
(就像它在“正常”类型的扣除)。对于这一点,我想答案是“完美转发” .`
编辑:更详细,可以考虑在这里你完全向前迈进了一类构造函数的情况下:
struct Widget //... to stay in Scott Meyers terminology
{
double &x;
Widget(double &_x) : x(_x) {}
};
class Manager : public Widget
{
template<typename ... Args>
Manager(Args&& ... args) : Widget(std::forward<Args>(args) ...) {}
};
如果调用Manager
通过
double d=1.0;
Manager(d);
的Args&&...
类型被推断double &
,根据规则,你我ntioned。由此,Manager
类的构造表现为
Manager(double &d) : Widget(std::forward<double&>(d)) {}
的std::forward<double &>(d)
效果就基本上一个static_cast<double&&>((double &) d)
,其通过引用折叠的规则仍然(double &) (d)
。因此,构造变得
Manager(double &d) : Widget((double &) d) {}
这样,变量正确传递给类Widget
,并且它也确保了正确的构造 - 一个将参考 - 被调用。
相反,如果该类型没有推导出double &
,而是作为double
,则Manager
类的构造函数会表现得像
Manager(double &d) : Base(std::forward<double>(d)) {}
成为翻译成
Manager(double &d) : Base((double &&) (d)) {}
也就是说,左值引用被转换为右值引用( - 好像已经应用了std::move
)。
有了这个,可能仍然可以参考,因为演员没有改变变量的地址。但是,现在您无法确定调用了Widget
中的正确构造函数 - 还可能有另一个正在使用右值引用,然后会错误地调用它。
请注意,当“X”是引用类型时,您呈现的示例会变得不正确。 '双&'。在这种情况下,'X'仍然会被推断为'double',但参数类型是'double&',因此它们是不同的。没有单一类型'X',而是两种类型,即推导类型和参数类型。 – davidhigh 2014-10-31 13:18:03