Проблема с примером после [conv.lval2.2]

#c #language-lawyer

#c #язык-юрист

Вопрос:

Пример:

 struct S { int n; };
auto f() {
S x { 1 };
constexpr S y { 2 };
return [amp;](bool b) { return (b ? y : x).n; };
}
auto g = f();
int m = g(false);   // undefined behavior: access of x.n outside its lifetime
int n = g(true);    // OK, does not access y.n
 

Соответствующее правило:

Когда преобразование lvalue в rvalue применяется к выражению E, и либо

  1. E потенциально не оценивается, или
  2. оценка E приводит к оценке члена ex набора потенциальных результатов E, и ex называет переменную x, которая не является odr-используемой ex([basic.def.odr])

значение, содержащееся в объекте, на который ссылается ссылка, недоступно.

Я сомневаюсь в выражении y.n , которое отмечено как не используемое odr n .

В соответствии с правилом:

Набор потенциальных результатов выражения E определяется следующим образом:

  • Если E является id-выражением ([expr.prim.id ]), набор содержит только E.
  • […]
  • Если E является выражением доступа к члену класса ([expr.ref]) формы E 1 . шаблон opt E 2 именует нестатический элемент данных, набор содержит потенциальные результаты E 1 .

Согласно пуле 3, потенциальный результат выражения y.n является y самим собой и n действительно является членом y , который является потенциальным результатом y.n . Однако я не согласен с тем, что n не используется odr.

В соответствии с этим правилом:
basic.def.odr #4.2

Переменная x, имя которой отображается как потенциально оцениваемое выражение E, является odr-используемой E, если только

  • x — это переменная не ссылочного типа, которая может использоваться в постоянных выражениях и не имеет изменяемых подобъектов, а E — элемент набора потенциальных результатов выражения энергонезависимого типа, не относящегося к классу, к которому выполняется преобразование lvalue в rvalue ([conv.lval]) применяется.

Преобразование lvalue в rvalue применяется к выражению y.n , потенциальные результаты которого содержат только выражение объекта y , а не n . Следовательно, согласно [basic.def.odr#4.2], переменная с именем n odr используется выражением n . Итак, g(true) должно быть неопределенное поведение. Как интерпретировать этот пример? Это неправильный пример?

Комментарии:

1. n не содержится в наборе потенциальных результатов (b ? y : x).n и, следовательно, odr-use просто не может к нему применяться.

2. @LanguageLawyer Да, я это знаю. я неправильно понимаю, что оценка E приводит к оценке члена Ex набора потенциальных результатов E. Я думал, что данные члена потенциального результата (y или x) из E.

3. И S::n , в конце концов, не является переменной.

4. @LanguageLawyer вы имеете в виду, что since S::n не является объектом, поэтому это не переменная для basic # 6 , верно?

5. s.n является объектом, но n все еще не переменной

Ответ №1:

Проблема с вашими рассуждениями заключается в том, что [conv.lval]/3.2 не требуется n использовать не-odr. Рассматриваемое выражение E = (b ? y : x).n . Набор потенциальных результатов таков {x, y} . Оценка E , когда b = true , в конечном итоге приведет к оценке y . Поэтому мы можем установить Ex = y , и теперь мы обнаруживаем, что «оценка E результатов при оценке члена Ex набора потенциальных результатов E » является истинным утверждением. Теперь предложение требует только, чтобы Ex = y имена переменной, в которой не используется odr Ex . Позвольте мне повторить это, поскольку я думаю, что именно здесь вы ошиблись: [conv.lval]/3.2 спрашивает, использует ли Ex odr себя (или, действительно, переменную, которую он называет). То, что мы ищем, — это доказательство того, что выражение y не использует переменную odr y . Доступ участника к n не имеет значения.

Что ж, мы продолжаем, рассматривая [basic.def.odr]/4

Переменная x , имя которой отображается как потенциально оцениваемое выражение E , используется odr E , если

  • x является переменной не ссылочного типа, которая может использоваться в постоянных выражениях и не имеет изменяемых подобъектов, и E является элементом набора потенциальных результатов выражения энергонезависимого типа, не относящегося к классу, к которому применяется преобразование lvalue в rvalue ( [conv.lval] ), или

Обратите внимание, что E here — это не E = (b ? y : x).n то, с чего мы начали [const.lval]/3.2 . E это выражение, которое мы тестируем на использование odr y . Давайте назовем это E' . Затем E' = Ex = y , потому что, опять же, мы проверяем, использует ли выражение y odr переменную y . Первая часть условия выполняется; y это переменная не ссылочного типа, которая может использоваться в постоянных выражениях и не имеет изменяемых подобъектов. Теперь, является E' = y ли элемент набора потенциальных результатов исходным E (потому E что это выражение энергонезависимого квалифицированного неклассового типа, к которому применяется преобразование lvalue в rvalue)? Да, мы уже говорили об этом, y это один из потенциальных результатов E . Следовательно, Ex не использует odr y . Это завершает предварительное условие для [conv.lval]/3.2 : теперь мы знаем, что (b ? y : x).n оно не обращается к значению y.n при вычислении преобразования lvalue в rvalue. Следовательно, нет никакого UB. Опять же, обратите внимание, что n в основном это вообще не фигурировало в наших рассуждениях.

Комментарии:

1. набор потенциальных результатов E ( (b ? y: x).n ) — это набор потенциальных результатов (b? x: y) , согласно basic.def.odr #2.7 , которые, в свою очередь, потенциальным результатом являются y и x . Итак, набор потенциальных результатов (b?y:x).n) равен {y,x}, верно? Утверждение «оценка E приводит к оценке члена Ex набора потенциальных результатов E» требует x или y нет odr-used только соответствующего выражения. И, согласно моему пониманию для [basic.def.odr #4.2], переменная с именем y не используется odr y .