Проект C ++ 14 (N3936) гласит в п. 3.2 / 3:
Переменная x, имя которой появляется в качестве потенциально вычисляемого выражения ex, используется odr, если только при применении преобразования lvalue-to-rvalue (4.1) в x не получается константное выражение (5.19), которое не вызывает никаких нетривиальных функций и, если x является объектом, ex является элементом набора потенциальных результатов выражения e, где либо преобразование lvalue-в-значение (4.1) применяется к e, либо e является выражением отброшенного значения (раздел 5).
Это не имеет никакого смысла для меня: если выражение e
это выражение отброшенного значения зависит от контекста, в котором e
используется. Каждое выражение, используемое в Выражение-заявление (§6.2) является выражение отброшенного значения. Если преобразование lvalue в rvalue применяется к e
также зависит от контекста e
используется в.
Более того, что означает выражение для множества потенциальные результаты другого выражения. Нужно понятие равенства выражений, чтобы определить членство в наборе. Но у нас нет ссылочная прозрачность, поэтому я не вижу, как этого можно достичь.
Почему это было изменено с C ++ 11 на C ++ 14? И как это следует интерпретировать? Как оно есть, это не имеет смысла.
Неформально, УСО использование переменной означает следующее:
Если какое-либо выражение где-либо в программе принимает адрес или привязывает ссылку непосредственно к объекту, этот объект должен быть определен.
В последней версии спецификации §3.2 была уточнена (см. Проект C ++ 14 на GitHub):
2 Выражение потенциально оценивается, если оно не является неоцененным операндом (раздел 5) или его подвыражением. Множество потенциальных результатов выражения
e
определяется следующим образом:[Примечание: этот набор является (возможно, пустым) набором выражений id, каждое из которых является
- Если
e
является id-выражением (5.1.1), набор содержит толькоe
,- Если
e
является выражением доступа к члену класса (5.2.5), набор содержит потенциальные результаты выражения объекта.- Если
e
является выражением указателя на член (5.5), второй операнд которого является константным выражением, набор содержит потенциальные результаты выражения объекта.- Если
e
имеет вид (e1), множество содержит потенциальные результаты e1.- Если
e
является условным выражением glvalue (5.16), набор является объединением наборов потенциальных результатов второго и третьего операндов.- Если
e
является выражением запятой (5.18), множество содержит потенциальные результаты правого операнда.- В противном случае набор пуст.
e
или подвыражениеe
, [Пример: в следующем примере набор потенциальных результатов инициализатораn
содержит первыйS::x
подвыражение, но не второеS::x
подвыражения.struct S { static const int x = 0; }; const int &f(const int &r); int n = b ? (1, S::x) // S::x is not odr-used here : f(S::x); // S::x is odr-used here, so // a definition is required
— конец примера] — конец заметки]
3 переменная
x
чье имя появляется как потенциально оцененное выражениеex
используется odr отex
если только не применить преобразование lvalue-в-значение (4.1) кx
дает постоянное выражение (5.19), которое не вызывает никаких нетривиальных функций и, еслиx
это объект,ex
является элементом множества потенциальных результатов выраженияe
где преобразование lvalue-в-значение (4.1) применяется кe
, или жеe
является выражением отброшенного значения (раздел 5).
§ 3.2 / 2 в C ++ 11 гласит:
Выражение потенциально оценивается, если оно не является неоцененным операндом (раздел 5) или его подвыражением. Переменная, имя которой появляется в качестве потенциально оцениваемого выражения, используется odr, если только она не является объектом, удовлетворяющим требованиям для появления в константном выражении (5.19), а преобразование lvalue-в-значение (4.1) равно немедленно применяется.
Проблема с этими формулировками была DR 712. Рассмотрим этот пример:
struct S {
static const int a = 1;
static const int b = 2;
};
int f(bool x) {
return x ? S::a : S::b;
}
поскольку S::a
а также S::b
lvalues условное выражение x ? S::a : S::b
это также lvalue. Это означает, что преобразование lvalue в rvalue не сразу применительно к S::a
а также S::b
, но к результату условного выражения. Это означает, что согласно формулировке C ++ 11, эти статические члены данных используются odr, и требуется определение. Но на самом деле используются только значения, поэтому нет необходимости определять статические элементы данных — достаточно объявления. Новая редакция проекта C ++ 14 решает эту проблему.
Нет. В следующем примере переменная S::a
все еще используется odr:
struct S { static constexpr int a[2] = {0, 1}; };
void f() {
auto x = S::a[0];
}
Поэтому я представил новый вопрос добавить следующий пункт в п. 3.2 / 2:
- если
e
является выражением подписи glvalue (5.2.1) видаE1[E2]
, набор содержит потенциальные результатыE1
,