万能引用 (Universal Reference)
C++ 中有左值引用和右值引用。左值引用可以绑定到左值,右值引用可以绑定到右值。那有没有一种引用,既可以绑定左值又可以绑定右值呢?有的,那就是我们这篇文章的主角,万能引用。万能引用在英文中称为 Universal Reference。它的形式为 T&&,并且这里的 T 是需要进行推导的类型。 如果读者感兴趣的话,可以看一下 Scott Mayers 的这篇博文。他讲得特别得详细,建议读者都看一下。本文基本上就是基于 Scott 的这篇博文进行了精简和整理。 万能引用在代码中大概是这样出现的: template <typename T> void foo(T &&x) {} auto &&x = ..; decltype(bar) &&x = ..; 万能引用中的型别推导 a) auto, template 在模板和 auto 型别推导形式下的万能引用,T 型别的左值被推导为 T&,而 T 型别的右值被推导为 T。 template <typename T> void foo(T &&x) {} int x = 1; foo(x); // T deduces to be int& foo(1); // T deduces to be int 上面的代码中使用了引用折叠的规则,对此尚不清楚的读者可以参考我的另一篇文章。 这条规则有一条隐藏的含义,那就是初始化值的引用类型在推导过程中被忽略了。不论初始化值是左值引用还是右值引用,或者是不是引用,都不影响推导的结果。非引用的左值,左值引用和右值引用都是左值,所以推导得到的型别 T 都是 T&;而只有右值会被推导为 T。 根据这条规则和引用折叠的规则,我们可以得到一条推论: 如果初始化值为左值,那么万能引用实例化为左值引用;如果初始化值为右值,那么万能引用实例化为右值引用。 int x = 1; auto &&y = x; // 因为 x 是左值,所以 y 的类型为 T& &&,折叠为 T& 即左值引用 auto &&p = y; // 同上,y 是左值 auto &&z = 1; 初始化值为右值,所以 z 的类型为 T &&,即右值引用 b) decltype 在 decltype 推导形式下的万能引用,初始化值的引用性得以保留。也就是说,如果初始化值为非引用左值,那么推导得到的型别为 T (而非 T&);如果初始化值为左值引用,那么推导得到的型别为 T&;如果初始化值为右值引用,那么推导得到的型别为 T&&。根据这条规则和引用折叠的规则,我们可以总结出这种形式下的万能引用的场景: ...