Тип повернення '?:' (Потрійний умовний оператор)


208

Чому перший повертає посилання?

int x = 1;
int y = 2;
(x > y ? x : y) = 100;

Поки другий ні?

int x = 1;
long y = 2;
(x > y ? x : y) = 100;

Насправді, друге взагалі не складено - "не оцінено ліворуч від завдання".


1
Гм, ось як знайти спеціальний футляр для випікання хліба, не прийшов до цього одного разу
Ulterior


Оскільки присвоєння виду виразу означало б принаймні один термін, цей термін більше не буде l-значенням.
Ів Дауст

Відповіді:


173

У виразах немає типів повернення, вони мають тип і - як відомо в останньому стандарті C ++ - категорію значень.

Умовним виразом може бути рівнезначення або ревалю . Це його ціннісна категорія. (Це дещо спрощення, C++11оскільки у нас є lvalues, xvalues ​​і prvalues.)

У дуже широкому та простому значенні lvalue означає об'єкт у пам'яті та rvalue - це просто значення, яке не обов'язково може бути приєднане до об'єкта в пам'яті.

Вираз присвоєння присвоює значення об'єкту, тому річ, якій призначено, повинна бути значенням .

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

ISO / IEC 14882: 2011 посилання:

3.10 [basic.lval] Значення та оцінки (про категорії цінностей)

5.15 [expr.cond] Умовний оператор (правила щодо того, який тип та значення значення має умовний вираз)

5.17 [expr.ass] Оператори присвоєння та складання присвоєння (вимога, щоб lhs присвоєння повинні бути змінним значенням)


3
І при читанні на xvalue і prvalue (так як я ніколи не чув про них , перш ніж ваш відповідь) я натрапив на цей зручний С.О. пост: stackoverflow.com/questions/3601602 / ...
пухнасту

an rvalue is just a value that may not necessarily be *attached* to an object in memory.Чи можете ви пояснити це більш простим терміном? . Також що ви маєте на увазі під type and value *category*? Спасибі
містер Анубіс

@SoulReaper: prvalue, xvalue, glvalueце цінні категорії.
Xeo

@Xeo Я ціную допомогу, але чи можете ви сказати, що він розуміє під rvalue - це лише значення, яке не обов'язково може бути приєднане до об'єкта в пам'яті. ? з прикладом?
Містер Анубіс

@SoulReaper: Я думаю , що він говорить про таких речах , як true, this, enumцінність. Ці речі є prvalues ​​("чисті" rvalues), але не живуть в пам'яті.
Xeo

57

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


але y більше, ніж x, тому немає потреби в просуванні для цього конкретного випадку, він може повернути посилання на y. Хм ... Але я згоден, це було б дивно.
Йола

1
@ Mr.TAMER: Я б швидше перекопав стандарт. : <
Xeo

3
@Yola: Оскільки типи є концепцією часу компіляції в C ++, фактичне значення повернення виразу не має значення.
Ксео

1
Ви не отримуєте посилання назад, ви отримуєте значення.
Сума

1
@Xeo: Хоча не в термінології C ++;)
Себастьян Мах

19

Він не може повернути значення значення, оскільки йому доведеться неявно просувати тип xвідповідності типу y(оскільки обидві сторони :не є одним і тим же типом), і з цим він повинен створити тимчасовий.


Що говорить стандарт? ( n1905 )

Вирази 5.17 Оператори призначення та складання операторів

5.17 / 3

Якщо другий і третій операнди мають різні типи, або має або тип (можливо, cv-кваліфікований) клас класу, робиться спроба перетворення кожного з цих операндів у тип іншого. Процес визначення, чи може вираз операнда E1 типу T1 перетворити на вираз операнда E2 типу T2, визначається наступним чином:

- Якщо E2 є значенням: E1 можна перетворити на відповідність E2, якщо E1 можна неявно перетворити (п. 4) у тип "посилання на T2", за умови обмеження, що при перетворенні посилання має пов'язуватися безпосередньо (8.5.3 ) до Е1.

- Якщо E2 є рейтингом, або якщо перетворення, описане вище, неможливо:

- якщо E1 і E2 мають тип класу, а базові типи класів однакові або один є базовим класом іншого: E1 можна перетворити на відповідність E2, якщо клас T2 того ж типу, або базовий клас , клас T1 і cv-кваліфікація T2 є такою ж cv-кваліфікацією, що і, або більша cv-кваліфікація, ніж cv-кваліфікація T1. Якщо застосовується перетворення, E1 змінюється на ревальвінг типу T2, який все ще посилається на оригінальний об'єкт класу-джерела (або відповідний його суб'єкт). [ Примітка: тобто копія не робиться. - кінцева примітка ] шляхом ініціалізації копіювання тимчасового типу T2 від E1 та використання цього тимчасового в якості перетвореного операнда.

В іншому випадку (тобто, якщо E1або E2 має тип не класу, або якщо вони обидва мають типи класів, але базові класи не є однаковими, або один базовий клас іншого): E1 може бути перетворений у відповідність E2, якщо E1 може бути неявно перетворений у тип, який мав би вираз E2, якби E2 було перетворено в rvalue (або тип, який він має, якщо E2 є rvalue).

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


5.17 / 4

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


5.17 / 5

В іншому випадку результат - ревальвація. Якщо другий та третій операнди не мають одного типу, або мають або тип класу (можливо, що відповідає кваліфікації cv), роздільна здатність перевантаження використовується для визначення перетворень (якщо такі є), що застосовуються до операндів (13.3.1.2, 13.6) . Якщо роздільна здатність перевантаження не вдається, програма неправильно сформована. В іншому випадку, визначені таким чином перетворення застосовуються, а перетворені операнди використовуються замість вихідних операндів на залишок цього розділу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.