C++面试题:万能引用与右值引用的区别
为了更好地理解模版,你需要知道万能引用,在模版推导中,它有着特殊的规则。在这篇文章里,我将教你区分万能引用和右值引用。
定义:万能引用可用于绑定左值和右值,只会出现在模版函数的入参中或者auto的推导中;右值引用只能用于绑定右值。例子如下:
void f(Widget&& param); // 右值引用
Widget&& var1 = Widget(); // 右值引用
auto&& var2 = var1; // 万能引用!!!
template<typename T>
void f(std::vector<T>&& param); // 右值引用
template<typename T>
void f(T&& param); // 万能引用
注:万能引用可以绑定左值,也可以绑定右值,还可以绑定const对象、volatile对象、const volatile对象,而右值引用只能绑定右值,不能绑定左值。例子如下:
// 万能引用
template<typename T>
void f(T&& param); // 万能引用
int x = 27;
const int cx = x;
const int& rx = x;
f(cx); // T的类型是const int&,param类型也是const int&
f(rx); // T的类型是const int&,param类型也是const int&
f(27); // T的类型是int,param类型是int&&
要使一个引用成为万能引用,其涉及类型推导是必要条件,但不是充分条件。比如:形如“T&&”也必要条件(包括auto和参数化模板),但是在T&&中加上const就不是万能引用了。以下例子:
// 有类型推导,但是是右值引用
template<typename T>
void f(std::vector<T>&& param); // 右值引用
std::vector<int> v;
f(v); // 错误,右值引用不能绑定左值!!
// 加了cosnt饰词后是右值引用
template<typename T>
void f(const T&& param); // param是右值引用!!!!!
但即使位于模板内的“T&&”,也有可能不是万能引用。
template<class T, class Allocator = allocator<T>>
class vector {
public:
void push_back(T&& x); // 不是万能引用。
};
std::vector<Widget> v; // 因为声明vector这个class后,T就具象化了,所以上面是一个右值引用!!
万能引用可以用于Args&&...args这种参数化模板。
template<class T, class Allocator = allocator<T>>
class vector {
public:
// Args是独立于vector的型别形参T的参数包。
template<class... Args>
void emplace_back(Args&&... x); // Args中每一个参数都是万能引用!!
};
auto&&是万能引用,因为它自带型别推导。
auto timeFuncInvocation =
[](auto&& func, auto&&... params) { // auto&&用于lambda的形参推导!!
// forward+decltype的组合
// 调用func,取用params。
std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)); // 见条款33
};
聊完以上知识点,感觉自己的C++技能又提升了一点。希望以上剖析的思路,能有效地帮助你学习以下经典C++书籍。
#C++#