简体   繁体   中英

Why is a reference type an lvalue when accessed with a temporary object?

Why does assigning a value to a reference variable being accessed using a temporary object work, but not for a non-reference type?

class a
{
    public:
        int m;
        int &n;
        a():m(2),n(m)
        {
            cout<< "A's constructor"<<endl;
        }
};

int main()
{
    // a().m = 6; // this gives an error that a temporary object is being used 
                  // as an lvalue
    a().n = 20;   // But this line works

    return 0;
}

But is a().n truely a temporary? Consider this code:

class a
{
    public:
        int m;
        int &n;
        a():m(2),n(m)
        {
            cout<< "A's constructor"<<endl;
        }

        a(int& _n):m(2),n(_n)
        {
            cout<< "A's constructor"<<endl;
        }
};

int main()
{
    a().n = 20;   // (1)

    int n = 0;
    a(n).n        // (2)

    return 0;
}

The line (2) clearly shows that .n is not a temporary. It must not be, since it's a reference to the local n variable.

But then, the compiler cannot know what n will refer. One could even do n(rand_bool()? m: _n) and it must work.

The compile instead uses the type system to know what should be assigned or not.

For example, the literal 9 is a pr-value of type int . You can't assign to it:

9 = 8; // nope

In your code, a() is a prvalue or type a . All of its value member also are. This is why a().m won't work. m is a prvalue.

But, a().n is an lvalue because n is a lvalue reference. No matter to which variable it points to.

a().n = 20;

works since n is a lvalue reference type. The compiler does not know that n is a reference to m in the implementation. It assumes that n is a valid lvalue reference and hence accepts that line.

In theory, when you assign to a().n , you could be assigning to a variable that lives independent of the life of a() . The compiler has no way of assessing that and will be in the way of the programmer if it didn't accept that line. Imagine the use case below:

// Global variable.
int gv;

class a
{
    public:
        int m;
        int &n;
        a():m(2), n(gv)  // n is a reference to the global variable.
        {
            cout<< "A's constructor"<<endl;
        }
};

int main()
{
    a().n = 20;   // Changes gv. It is a valid operation.
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM