Почему типом результата условного выражения является константная ссылка?

Есть фрагмент кода:

int x = 0;
const int y = 0;
decltype(auto) z = true ? x : y;
static_assert(std::is_same_v<const int&, decltype(z)>);

Согласно [expr.cond], второй операнд x неявно преобразуется в const int&, а третий операнд y имеет тип const int, который отличается от const int&, поэтому программа должна быть неправильно сформирована.

Очевидно, я ошибаюсь, но я не знаю, в чем дело? Или какой конкретный процесс определяет тип выражения как const int&?

почти уверен этот раздел означает, что x становится const int, поэтому обе стороны становятся const int, а z становится const int&

NathanOliver 18.04.2024 00:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
102
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Конечно, y имеет тип const int, но он не появляется в выражении утверждения; что в этом неправильного? Согласно пункту 4.1 ссылочного документа, все условное выражение имеет ссылочный тип, поэтому z объявляется как ссылка, которая удовлетворяет утверждению.

В конце раздела 4 сказано, что преобразование применяется к выбранному операнду, поэтому x после преобразования имеет тип, отличный от y, поэтому оставшийся подпункт, по-видимому, неприменим.

ValueError 18.04.2024 01:29
Ответ принят как подходящий

Это условное выражение регулируется [expr.cond]/4, которое я частично цитирую:

В противном случае, если второй и третий операнд имеют разные типы и либо имеют тип класса (возможно, с указанием cv), либо оба являются glvalues ​​одной и той же категории значений и одного и того же типа, за исключением уточнения cv, предпринимается попытка сформировать последовательность неявного преобразования каждого из этих операндов в тип другого. [...] Предпринимаются попытки сформировать последовательность неявного преобразования из выражения операнда E1 типа T1 в целевой тип, связанный с типом T2 выражения операнда E2, следующим образом:

  • Если E2 является lvalue, целевым типом является «ссылка lvalue на T2», но последовательность неявного преобразования может быть сформирована только в том случае, если ссылка будет напрямую привязана ([dcl.init.ref]) к glvalue.
  • [...]

С помощью этого процесса определяется, может ли быть сформирована последовательность неявного преобразования из второго операнда в целевой тип, определенный для третьего операнда, и наоборот. Если обе последовательности могут быть сформированы или одна может быть сформирована, но это неоднозначная последовательность преобразования, программа является неправильной. Если последовательность преобразования не может быть сформирована, операнды остаются неизменными и дальнейшая проверка выполняется, как описано ниже. В противном случае, если может быть сформирована ровно одна последовательность преобразования, это преобразование применяется к выбранному операнду, и преобразованный операнд используется вместо исходного операнда в оставшейся части этого подраздела. [...]

x и y — это «glvalues ​​одной и той же категории значений» (поскольку они оба являются lvalue) и одного типа, за исключением cv-квалификации, поэтому применим этот маркированный список. Принимая E1 за x, а E2 за y, поскольку y является lvalue, применяется первый пункт ([expr.cond]/4.1): целевой тип, в который нужно преобразовать x, — это «ссылка lvalue на const int». Поскольку такое преобразование возможно (а обратное преобразование невозможно(1)), преобразование применяется.

После этого шага условное выражение выглядит как true ? static_cast<const int&>(x) : y.

Обратите внимание, что второй и третий операнд теперь являются значениями типа const int. Выражения не имеют ссылочного типа; выражение, которое имеет ссылочный тип lvalue, на самом деле является просто lvalue ссылочного типа (см. [expr.type]/1).

Итак, мы переходим к [expr.cond]/5:

Если второй и третий операнды являются glvalues ​​одной и той же категории значений и имеют один и тот же тип, результат имеет этот тип и категорию значения и является битовым полем, если второй или третий операнд является битовым полем или если оба являются битовыми полями.

Второй и третий операнд теперь являются glvalue одной и той же категории значений (lvalue) и того же типа (const int), поэтому результатом является lvalue const int, и все готово.

Когда вы применяете decltype к такому выражению, оно дает вам тип, а затем добавляет к нему &, чтобы сообщить вам, что выражение является lvalue ([dcl.type.decltype]/1.5).


(1) Обратное преобразование y в «ссылку lvalue на int» невозможно, поскольку при этом квалификатор const будет отброшен.

«Выражения не имеют ссылочного типа...» У них действительно есть ссылочный тип, как утверждает и объясняет Скотт Мейерс. Обратите внимание, что он также сказал в своей статье/объяснении: «Совершенно очевидно, что выражения могут иметь ссылочный тип».

user12002570 19.04.2024 16:53

@user12002570 user12002570 У них есть ссылочный тип на короткое время, когда с ними невозможно что-либо сделать, прежде чем они будут настроены, поэтому я предпочитаю думать о [expr.type]/1 как о чистом правиле построения.

Brian Bi 19.04.2024 17:34

Да, технически выражения имеют ссылочный тип. Хотя неформально, как вы сказали, часто бывает полезно сразу подумать о типе после корректировки. Но мы все равно должны явно упомянуть, что стандарт позволяет выражениям иметь ссылочный тип (даже если это только до настройки и на короткое время).

user12002570 20.04.2024 04:12

Другие вопросы по теме