C++面试题:万能引用与右值引用的区别

alt 为了更好地理解模版,你需要知道万能引用,在模版推导中,它有着特殊的规则。在这篇文章里,我将教你区分万能引用和右值引用。

定义:万能引用可用于绑定左值和右值,只会出现在模版函数的入参中或者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++书籍。

alt

#C++#
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务