Когда переменная odr используется в C ++ 14?

Проект 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? И как это следует интерпретировать? Как оно есть, это не имеет смысла.

25

Решение

Цель использования odr

Неформально, УСО использование переменной означает следующее:

Если какое-либо выражение где-либо в программе принимает адрес или привязывает ссылку непосредственно к объекту, этот объект должен быть определен.

Разъяснение в последнем проекте

В последней версии спецификации §3.2 была уточнена (см. Проект C ++ 14 на GitHub):

2 Выражение потенциально оценивается, если оно не является неоцененным операндом (раздел 5) или его подвыражением. Множество потенциальных результатов выражения e определяется следующим образом:

  • Если e является id-выражением (5.1.1), набор содержит только e,
  • Если e является выражением доступа к члену класса (5.2.5), набор содержит потенциальные результаты выражения объекта.
  • Если e является выражением указателя на член (5.5), второй операнд которого является константным выражением, набор содержит потенциальные результаты выражения объекта.
  • Если e имеет вид (e1), множество содержит потенциальные результаты e1.
  • Если e является условным выражением glvalue (5.16), набор является объединением наборов потенциальных результатов второго и третьего операндов.
  • Если e является выражением запятой (5.18), множество содержит потенциальные результаты правого операнда.
  • В противном случае набор пуст.
[Примечание: этот набор является (возможно, пустым) набором выражений id, каждое из которых является 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).

Какова была ситуация в C ++ 11?

§ 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,
26

Другие решения


По вопросам рекламы [email protected]