#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, и либо
- E потенциально не оценивается, или
- оценка 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
, используется odrE
, если
- …
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 не используется odry
.