Вызывает ли сравнение между Lvalue и литералом преобразование Lvalue в Rvalue?

Я задал этот вопрос: static_assert of const Variable

И, по-видимому, все сводится к вопросу, преобразуется ли значение lvalue с плавающей запятой в значение r для целей сравнения?

Итак, в этом коде происходит преобразование lvalue в rvalue?

const float foo = 13.0F;
static_assert(foo > 0.0F, "foo must be greater than 0.");

person Jonathan Mee    schedule 27.10.2017    source источник
comment
foo это float. 0.0 это double. Должно быть преобразование для сравнения двух типов, поскольку исходные типы не совпадают.   -  person Jesper Juhl    schedule 27.10.2017
comment
@JesperJuhl Спасибо, я сделал ошибку копирования и вставки. Я исправил это. Я спрашиваю о случае, когда литерал того же типа, что и lvalue.   -  person Jonathan Mee    schedule 27.10.2017
comment
Кого это может касаться, это кажется камнем преткновения в разделе значений и выражений этого ответа   -  person Jonathan Mee    schedule 30.10.2017


Ответы (1)


Да, выполняется. По сути, это все потому, что 3.0 > 1.2 — это правильно сформированное выражение, которое не содержит ничего, кроме prvalues ​​для операндов.

Во-первых, [expr]/9 утверждает (выделено мной), что

Всякий раз, когда выражение glvalue появляется как операнд оператора, который ожидает значение prvalue для этого операнда, к ним применяются стандартные преобразования lvalue-to-rvalue, массива в указатель или функции в указатель. преобразовать выражение в prvalue.

Таким образом, вопрос на самом деле сводится к "Ожидают ли реляционные операторы ожидание значений prvalue для операндов"? И ответ на это тоже да. Поскольку нам нужно учитывать [expr.rel]/1 :

relational-expression:
  shift-expression
  relational-expression < shift-expression
  relational-expression > shift-expression
  relational-expression <= shift-expression
  relational-expression >= shift-expression

Операнды должны иметь арифметический тип, тип перечисления или указатель. Все операторы ‹ (меньше), > (больше), ‹= (меньше или равно) и >= (больше или равно) дают значение false или true. Тип результата — bool.

Вышеупомянутое производство грамматики является важным моментом. Мы можем следовать ему (я не буду делать это полностью здесь) и уменьшить shift-expression до primary-expression. И одно из произведений primary-expression - это literal. Для чего сказано в [expr.prim.literal]:

Литерал — это первичное выражение. Его тип зависит от формы. Строковый литерал — это lvalue; все остальные литералы являются значениями prvalue.

И поскольку большинство литералов являются значениями prvalue, я думаю, можно с уверенностью сказать, что реляционные операторы ожидают значения prvalue для операндов.

person StoryTeller - Unslander Monica    schedule 16.01.2018
comment
Это отличный ответ, но человек, если я не борюсь с glvalues ​​​​и prvalues. Мне приходится искать их каждый раз, когда я их читаю. rvalues ​​и lvalues ​​знакомы и безопасны для меня, так как они были в основном все время, пока я был программистом C++... Но... У вас есть эвристика или что-то, что вы используете, чтобы думать о glvalues ​​и ценит? - person Jonathan Mee; 16.01.2018
comment
@JonathanMee - я думаю, можно с уверенностью сказать, что значение prvalue очень похоже на то, что C считает значением r. т.е. все, что не может быть назначено. Чистое значение, возможно, без объекта для его резервного копирования. Значение gl — это все, что вы можете присвоить (при условии, что оно не является константой). Таким образом, любой объект вы можете назвать либо по фактическому имени, либо по ссылке (lvalue или rvalue ref) на него. За исключением UB, ссылка всегда включает упоминаемый объект, занимающий хранилище. Но, как и все эвристики, она достаточно часто меня подводит, хотя я могу обходиться ею, работая изо дня в день. - person StoryTeller - Unslander Monica; 16.01.2018