Статический констекстер одр-используется или нет?

Почему это работает на gcc но не на clang( посмотреть его вживую):

constexpr int giveMeValue() { return 42; }

struct TryMe {
  static constexpr int arr[1] = {
      giveMeValue()
  };  
};

int main() {
    int val = TryMe::arr[0];
    return val;
}

Я получаю неразрешенный внешний символ с лязгом.

Является TryMe::arr[0] объект? Если да, то используется ли он?

1 ответ

TryMe::arr используется odr, но вы не даете определение ( смотрите его вживую):

constexpr int TryMe::arr[1];

Почему результат несовместим между gcc а также clang? Это связано с тем, что нарушения odr не требуют дезагностики как из проекта стандарта C++11, так и из C++14 (выделено мое):

Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется в этой программе в виде odr; Диагностика не требуется.

Мы видим, что он используется в проекте стандарта C++11, раздел 3.2 который говорит:

Выражение потенциально оценивается, если оно не является неоцененным операндом (раздел 5) или его подвыражением. Переменная, имя которой появляется в качестве потенциально оцениваемого выражения, используется odr, если только она не является объектом, удовлетворяющим требованиям для появления в константном выражении (5.19), и преобразование lvalue-в-значение (4.1) применяется немедленно.

TryMe::arr является объектом, и он удовлетворяет требованиям для появления в константном выражении, но преобразование lvalue в rvalue не применяется немедленно к TryMe::arr но TryMe::arr[0],

Обновленная формулировка из проекта стандарта C++14, которая также применяется к C++11, поскольку она была применена в отчете о дефектах ( DR 712):

Переменная x, имя которой появляется в качестве потенциально оцениваемого выражения ex, используется odr, если только при применении преобразования lvalue-to-rvalue (4.1) в x не получается константное выражение (5.19), которое не вызывает никаких нетривиальных функций и, если x является объектом, ex является элементом набора потенциальных результатов выражения e, где к e применяется либо преобразование lvalue-в-значение (4.1), либо e является выражением отброшенного значения

Потенциальные результаты выражения TryMe::arr[0] пуст по критериям в 3.2 параграф 2 и поэтому он используется.

Примечание: вы должны предоставить определение вне класса согласно разделу 9.4.2 [class.static.data], который говорит (выделение мое):

Статический член данных литерального типа может быть объявлен в определении класса с помощью спецификатора constexpr; если это так, его объявление должно указывать инициализатор скобок или равных, в котором каждое предложение инициализатора, являющееся выражением присваивания, является константным выражением. [Примечание: в обоих этих случаях член может появляться в константных выражениях. - примечание] Элемент все еще должен быть определен в области пространства имен, если он используется в программе с помощью odr (3.2), и определение области пространства имен не должно содержать инициализатор

Обновить

TC указал на отчет о дефектах 1926 года, в котором добавлен следующий пункт 3.2 [basic.def.odr] пункт 2:

  • Если e - операция подписки (5.2.1 [expr.sub]) с операндом массива, набор содержит этот операнд.

Это означает, что подписка на массив больше не является использованием odr, и поэтому код OPs будет правильно сформирован в C++1z и выглядит как C++14, поскольку дефект выглядит так, как если бы он был против C++14.

Другие вопросы по тегам