Пример:
struct S { int n; };
auto f() {
S x { 1 };
constexpr S y { 2 };
return [&](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-to-rvalue применяется к выражению E, и либо
- E потенциально не оценивается, или
- оценка E приводит к оценке члена Ex набора потенциальных результатов E, а Ex называет переменную x, которая не используется Ex ([basic.def.odr])
значение, содержащееся в указанном объекте, недоступно.
Я сомневаюсь в выражении y.n
, которое отмечено как неиспользуемое из n
.
По правилу:
Множество потенциальных результатов выражения E определяется следующим образом:
- Если E является id-выражением ([expr.prim.id]), набор содержит только E.
- [...]
- Если E является выражением доступа к члену класса ([expr.ref]) формы E1 . шаблон opt E2, именующий нестатический член данных, набор содержит потенциальные результаты E1.
Согласно пуле 3, потенциальным результатом выражения y.n
является само y
, а n
действительно является членом y
, который является потенциальным результатом y.n
. Однако я не согласен с тем, что n
не используется.
Согласно этому правилу:
basic.def.odr#4.2
Переменная x, имя которой появляется как потенциально вычисляемое выражение E, используется E odr, если только
- x — это переменная нессылочного типа, которая может использоваться в константных выражениях и не имеет изменяемых подобъектов, а E — элемент множества потенциальных результатов выражения неклассового типа с неизменяемой квалификацией, к которому относится lvalue- Применяется преобразование в значение ([conv.lval]).
Преобразование lvalue-to-rvalue применяется к выражению y.n
, потенциальные результаты которого содержат только объектное выражение y
, а не n
. Следовательно, согласно [basic.def.odr#4.2], переменная с именем n
используется odr выражением n
. Итак, g(true)
должно быть неопределенным поведением. Как интерпретировать этот пример? Это неправильный пример?
@LanguageLawyer Да, я знаю это. что я неправильно понимаю, так это то, что оценка E приводит к оценке элемента Ex набора потенциальных результатов E. Я думал, что элемент данных потенциального результата (y или x) E.
И S::n
в конце концов не переменная.
@LanguageLawyer, вы имеете в виду, поскольку S::n
не является объектом, значит, это не переменная для basiC# 6, верно?
s.n
— это объект, но n
еще не переменная
@LanguageLawyer, почему n
все еще не является переменной? Я этого не понимаю. вы сказали, что s.n
— это объект, вы имеете в виду, что s
— это объект типа S
? Пожалуйста, интерпретируйте такие два вопроса.
Проблема с вашими рассуждениями заключается в том, что [conv.lval]/3.2
не требует, чтобы n
не использовался. Рассматриваемое выражение 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- применяется преобразование в значение ([conv.lval]
), или- ...
Обратите внимание, что E
здесь — это не 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
не использует запах y
. Это завершает предварительное условие для [conv.lval]/3.2
: теперь мы знаем, что (b ? y : x).n
не обращается к значению y.n
при оценке преобразования lvalue в rvalue. Поэтому УБ нет. Опять же, обратите внимание, что n
вообще не фигурировало в наших рассуждениях.
множество потенциальных результатов 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
.
n
не содержится в наборе потенциальных результатов(b ? y : x).n
и, следовательно, использование odr просто не может применяться к нему.