1 Востаннє редагувалося Yola (16.12.2016 10:53:12)

Тема: Чому приведення вказівника до іншого типу не повертає lvalue?

Чому приведення на кшталт такого не повертають lvalue?

ID3D12GraphicsCommandList* list;
(ID3D12CommandList*)list; // не lvalue отже я не можу використати &

Тільки не кажіть, що тому що стандарт забороняє. Чому він забороняє тоді?

----

Я тут виявив, що стандарт не гарантує, що всі вказівники мають однаковий розмір, але не певен, що це причина.

----

За запитом пана koala:

        ID3D12GraphicsCommandList* list;
        &(ID3D12CommandList*)list;

мене цікавить чому саме це не є lvalue. Яка рація?

2

Re: Чому приведення вказівника до іншого типу не повертає lvalue?

Вибачте, можете повністю навести код, що генерує помилку? Бо наразі нічого, окрім "бо перетворений об'єкт не є lvalue" сказати не можу.

3

Re: Чому приведення вказівника до іншого типу не повертає lvalue?

Ось таке знайшов:

Стандарт написав:

lvalue (...) позначає функцію чи об'єкт. ...
xvalue (“конаюче/eXpiring” значення) також покликається до об'єкта, ...
rvalue (...) це xvalue, тимчасовий об'єкт (12.2) або його підоб'єкт, або значення не пов'язане з якимсь об'єктом.
prvalue (“чисте/pure” rvalue) це rvalue, яке не xvalue. ...

Тобто вони вважають, що приведений вказівник це покликається ні до якого об'єкта. І от тут двозначність, якщо не всі вказівники однакового розміру, то після касту ми отримуємо вказівник із якимсь сміттям всередині, і тому це не lvalue. Чи, може, це тому, що якщо вказівник був на int, а тепер на long, то об'єкта типу long насправді не існує.

4

Re: Чому приведення вказівника до іншого типу не повертає lvalue?

Поясню на пальцях int-ах:

int x;
&(long)x;//помилка: ніякого об'єкту типу long не існує, отже, нема в чого брати адресу

5

Re: Чому приведення вказівника до іншого типу не повертає lvalue?

koala написав:

Поясню на пальцях int-ах:

int x;
&(long)x;//помилка: ніякого об'єкту типу long не існує, отже, нема в чого брати адресу

А вказівники де поділись?

6

Re: Чому приведення вказівника до іншого типу не повертає lvalue?

А яка різниця? Вказівники, структури, темплейти - не має значення, результат операції перетворення - це revalue.

7

Re: Чому приведення вказівника до іншого типу не повертає lvalue?

Давайте так: lvalue - це щось, що знаходиться в пам'яті і "живе" там певний час. rvalue - це проміжний результат обчислень, якщо він не буде використаний в подальших обчисленнях і не буде занесений в пам'ять, то зникне. Наприклад

a=2;//2-rvalue, a-lvalue
b=2+3*a;//a,b-rvalue (для a це несуттєво), 6 і 8 - lvalue.

Ви берете змінну list, яка, безумовно, є lvalue, і виконуєте із її значенням (підкреслюю-саме значенням) операцію. Яку саме - не має значення: перетворюєте, додаєте щось чи іншу, головне - результатом цієї операції буде значення, а не місце в пам'яті, що зберігає це значення. Відповідно, взяти адресу цього значення буде неможливо.
А заплуталися ви, мабуть, через те, що ні, телепатією я не займаюся. Я більше коду не бачив, тому і припускати не буду.

Подякували: Yola1

8 Востаннє редагувалося Reinterpret (19.12.2016 21:22:43)

Re: Чому приведення вказівника до іншого типу не повертає lvalue?

Yola написав:

Чому приведення на кшталт такого не повертають lvalue?

Ну, думаю тому, що є стандарт який говорить (справедливо і для кастів С-шного типу):

5.2.10 Reinterpret cast
1 The result of the expression reinterpret_cast<T>(v) is the result of converting the expression v to type T.
If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue
reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the lvalue-to-rvalue (4.1),
array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the expression v.

int main()
{
    int x = 42;
    int *pi = &x;

    //&(double*)pi; //error: lvalue required as unary '&' operand
    //&reinterpret_cast<double*>(pi); //error: lvalue required as unary '&' operand

    std::cout << &reinterpret_cast<double*&>(pi) // ok: lvalue
              << " == " << &pi;
}

(double*)pi; так само як і reinterpret_cast<double*>(pi); повертає rvalue і тому його адрес взяти не можливо.
Але можна скастити до double*& і без проблем взяти адрес оскільки результуючим типом буде lvalue.