现代C++技术研究(5)---什么是通用引用(Universal Reference)

通用引用(Universal Reference)是Scott Meyers首先提出的名词,实际上就是指编译时需要进行类型推导的右值引用形式的表达式,现在,很多人认为,更加标准的名称应该叫转发引用(Forwarding Reference)。C++ 98没有右值引用,右值引用是C++11引入的新特性。在C++98中,常量左值引用,可以绑定左值或右值,到C++11也依然如此,因此,把常量左值引用叫做通用引用貌似更合适一些。

本文还沿用Scott Meyers的命名。那么,如何区分通用引用和右值引用呢。对于通用引用(Universal Reference),有如下三个基本特征:

1)涉及编译时的类型推导

2)右值引用的形式&&

3)可以绑定左值(右值引用是不能绑定左值的)

下面的小程序列举了主要的测试场景:

#include 
#include 

template 
class MyVector {
public:
    void push_back(T&& x) // fully specified parameter type ⇒ no type deduction;     && ≡ rvalue reference
    { 
        using ParamType = T&&;
        bool isLeftValueRef = std::is_lvalue_reference::value;
        bool isRightValueRef = std::is_rvalue_reference::value;
        if (isLeftValueRef) {
            std::cout << "praram type is lvalue reference type\n";
        } 
        if (isRightValueRef) {
            std::cout << "praram type is rvalue reference type\n";
        }
    }
    template  void func(Tp&& x) // universal reference 
    {
        using ParamType = Tp&&;
        bool isLeftValueRef = std::is_lvalue_reference::value;
        bool isRightValueRef = std::is_rvalue_reference::value;
        if (isLeftValueRef) {
            std::cout << "praram type is lvalue reference type\n";
        } 
        if (isRightValueRef) {
            std::cout << "praram type is rvalue reference type\n";
        }        
    }
};

template
constexpr std::size_t arraySize2(T (&&)[N]) noexcept 
{// fully specified parameter type ⇒ no type deduction;  && ≡ rvalue reference
    return N;
}

template void f(T&& param) // universal reference 
{
    using ParamType = T&&;
    bool ParamTypeIsIntRef = std::is_same::value;
    bool ParamTypeIsConstIntRef = std::is_same::value;
    bool ParamTypeIsIntRefRef = std::is_same::value;
    if (ParamTypeIsIntRef) {
        std::cout << "param's type is int&\n";
    } else if (ParamTypeIsConstIntRef) {
        std::cout << "param's type is const int&\n";
    } else if (ParamTypeIsIntRefRef) {
        std::cout << "param's type is int&&\n";
    }
}

int main()
{
    int i = 0;
    int&& j = 2;   // rvalue reference
    auto&& k = i;  // universal reference deduce to lvalue reference
    const auto&& m = 5; // rvalue reference
    MyVector obj;
    obj.push_back(2); // fail to bind lvalue 
    obj.func(i); // universal reference 
    int keyVals[] = { 1, 3, 7, 9, 11, 22, 35 }; // keyVals has 7 elements
    int Num2 = arraySize2(std::move(keyVals)); // fail to bind lvalue
    int x = 27; // x is an int
    const int cx = x; // cx is a const int
    const int& rx = x; // rx is a reference to x as a const int
    f(x);  // x is lvalue, param's type is int&
    f(cx); // cx is lvalue, param's type is const int&
    f(rx); // rx is lvalue, param's type is const int&
    f(27); // 27 is rvalue, param's type is int&&
    return 0;
}

测试结果如下:

[root@192 moderncpp]# ./universal_reference
praram type is rvalue reference type
praram type is lvalue reference type
param's type is int&
param's type is const int&
param's type is const int&
param's type is int&&

参考资料:

"Universal reference" or "forwarding reference"? – Arthur O'Dwyer – Stuff mostly about C++

你可能感兴趣的:(C/C++技术,c++,开发语言)