Почему ссылочный тип является lvalue при доступе к временному объекту? - PullRequest
4 голосов
/ 29 октября 2019

Почему назначение значения для ссылочной переменной, доступ к которой осуществляется с использованием временного объекта, работает, но не для не ссылочного типа?

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;
}

Ответы [ 2 ]

2 голосов
/ 29 октября 2019

Но действительно ли a().n временно? Рассмотрим этот код:

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;
}

Строка (2) ясно показывает, что .n не является временным. Этого не должно быть, так как это ссылка на локальную переменную n.

Но тогда компилятор не может знать, на что будет ссылаться n. Можно даже сделать n(rand_bool() ? m : _n), и это должно сработать.

Компиляция вместо этого использует систему типов, чтобы знать, что должно быть назначено или нет.

Например, литерал 9 являетсяpr-значение типа int. Вы не можете присвоить ему:

9 = 8; // nope

В вашем коде a() - это значение или тип a. Все его члены значения также являются. Вот почему a().m не будет работать. m - это prvalue.

Но, a().n - это lvalue, потому что n - это ссылка на lvalue. Независимо от того, на какую переменную он указывает.

1 голос
/ 29 октября 2019
a().n = 20;

работает, поскольку n является ссылочным типом lvalue. Компилятор не знает, что n является ссылкой на m в реализации. Предполагается, что n является действительной ссылкой lvalue и, следовательно, принимает эту строку.

Теоретически, когда вы присваиваете a().n, вы можете назначать переменную, которая живет независимо от жизни a(). Компилятор не может оценить это и будет мешать программисту, если он не примет эту строку. Представьте пример использования ниже:

// 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...