在C++11之前,模板类型的推导非常简单:
template <typename X>
void bar(X i) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}类型X将是调用方传入的参数的任何类型。
现在,对于C++11,我阅读了一篇关于来自斯科特·迈尔斯的rvalue引用的文章。
它说
template<typename T>
void f(T&& param);在对作为通用引用的模板参数进行类型推导期间,将推导出相同类型的lvalue和rvalue具有稍微不同的类型。特别地,T型的r值是T型的,T型的r值是T型的,T型的r值是T型的。
我想知道为什么T型的r值是T型的,而T型的r值是T型的。
只是要记住些什么吗?或?
发布于 2014-10-31 11:45:12
唯一要回答的问题是,为什么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 &。这样,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)) {}也就是说,lvalue引用被转换为rvalue引用(--就像应用了std::move一样)。
这样,仍然可以接受引用,因为强制转换没有更改变量的地址。但是,现在您不能确定是否调用了Widget中的正确构造函数--还可能有另一个构造函数使用rvalue引用,该引用将被错误地调用。
发布于 2014-10-31 13:01:30
我认为原因是T和T&都表示作为参数类型出现的lvalue;只是T将lvalue表示为局部变量,而T&则表示“从其他地方到lvalue的别名”。
当为T、T&和T&&实例化时,泛型函数不太可能工作得很好,因为后者的语义与lvalue的语义非常不同。因此,如果您想要一个rvalue,您应该显式地声明它。
https://stackoverflow.com/questions/26673769
复制相似问题