"c++ 的 universal reference"

估计很多人都没有听说过 universal reference ,这个不奇怪,因为是 Scott Meyers 自己创造的这个术语,参考 https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers 。 C++ 标准里面没有这个术语,标准术语是 Reference collapsing 。但是 这种解释是更难理解,尽管更加准确。

Herb Sutter 同意这个东西应该有一个名字,但是应该叫做 forwarding reference。 因为 universal reference 似乎建议这个东西是更加通用的东西,到处都可以用,其实不是这样。 forwarding reference 则强调 这个东西只有在做 perfect forwarding 的时候才用。 关于 perfect forwarding ,看这里

我理解 scott meyers 的文章的意思只是指当看起来像右值引用的 T&& 出现在 template 的中,他就是 universal reference ,既不是 lvalue reference 也不是 rvalue reference

universal reference 的实际效果就是,你给他一个 lvalue reference 的时候,他就是 lvalue reference ,你给他 rvalue reference 的时候,他就是 rvalue reference 。

看下面的例子

#include <iostream>
#include <functional>
#include <boost/type_index.hpp>
using namespace std;

#define SHOW_TYPE_AND_SIZE(expr) if(1){             \
        cout << #expr << ":\n"; show_type_and_size(expr);   \
}while(0)


template<typename T>
void show_type_and_size(T&& x) {
    cout << "T = "
         << boost::typeindex::type_id_with_cvr<T>().pretty_name() << ";\n"
         << boost::typeindex::type_id_with_cvr<decltype(x)>().pretty_name() << " x;\n"
         << "sizeof(x) "  << sizeof(x) << "\n"
         << endl;
}
int foo() {
    return 100;
}
int main(int argc, char *argv[])
{
    int x = 100;
    int&& rf = foo();
    SHOW_TYPE_AND_SIZE(100);
    SHOW_TYPE_AND_SIZE(rf);
    SHOW_TYPE_AND_SIZE(foo());
    SHOW_TYPE_AND_SIZE(x);
    return 0;
}

输出如下:

100:
T = int;
int&& x;
sizeof(x) 4

rf:
T = int&;
int& x;
sizeof(x) 4

foo():
T = int;
int&& x;
sizeof(x) 4

x:
T = int&;
int& x;
sizeof(x) 4

这里需要注意,尽管 rf 的值是一个 rvalue reference ,但是他本身是一个 lvalue 。参考 C++11 的右值引用问题