Подтвердить что ты не робот

Являются ли элементы массива constexpr компиляцией констант времени?

Является ли фрагмент кода

struct Parameters {
   static constexpr int n = 2;
   static constexpr double v[n] = {4.0, 5.0};
};

юридический С++ 11? И если да, то константы времени Parameters::v[0] и Parameters::v[1] компилируются или просто указатель Parameters::v сам a constexpr (что бы это ни значило во время компиляции)?

Как вы можете видеть, я обычно немного запутался в массивах constexpr и их инициализации в классах/структурах. Пожалуйста, не стесняйтесь отвечать не только на мой конкретный вопрос, но также упомянуть об общих ловушках и т.д. Относительно этой темы.

4b9b3361

Ответ 1

Я не вижу проблемы с конструкцией. Цитирование С++ 11, [dcl.constexpr]:

§1 Спецификатор constexpr должен применяться только к определению переменной, объявлению функции или шаблон функции или объявление статического элемента данных литерала типа (3.9)....

§9. Спецификатор constexpr, используемый в объявлении объекта, объявляет объект как const. Такой объект должен иметь буквальный тип и должен быть инициализирован. Если он инициализируется вызовом конструктора, этот вызов должен быть константой выражение (5.19). В противном случае, или если спецификатор constexpr используется в описании ссылки, каждое полное выражение которое появляется в его инициализаторе, должно быть постоянным выражением. Каждое неявное преобразование, используемое в преобразование выражений инициализатора и каждый вызов конструктора, используемый для инициализации, должен быть одним из тех допускается в постоянном выражении (5.19).

double - это буквальный тип, а также массив литералов. Это означает, что v[0] и v[1] из вашего кода действительно являются постоянными выражениями.

Ответ 2

struct Parameters {
   static constexpr int n = 2;
   static constexpr double v[n] = {4.0, 5.0};
};

Этот фрагмент сам по себе, безусловно, является законным, насколько я могу судить. В разделе 7.1.5 [dcl.constexpr] из стандарта С++ 11 указано, что

Спецификатор constexpr применяется только к... объявлению статического элемента данных литерала типа

и тип литерала определен в 3.9:

Тип - это буквальный тип, если он:

- скалярный тип; или...

- массив литералов типа

Итак, static constexpr double v[2] = { ... }, безусловно, действителен, насколько я могу судить.

Что касается элементов массива constexpr... Я не уверен. Если мы объявим

constexpr double d = Parameter::v[1];

тогда как g++, так и clang компилируют его в порядке, но версия clang не может ссылаться на ссылку undefined на Parameters::v. Я не знаю, указывает ли это на ошибку Clang или недействительна конструкция.

Ответ 3

struct Parameters {
  static constexpr int n = 2;
  static constexpr double v[n] = {4.0, 5.0};
};

int main() {
  constexpr int a = Parameters::v[0];
  return 0;
}

Этот код в gcc 4.8.2 компилируется в следующее:

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   c7 45 fc 04 00 00 00    mov    DWORD PTR [rbp-0x4],0x4
   b:   b8 00 00 00 00          mov    eax,0x0
  10:   5d                      pop    rbp
  11:   c3                      ret 

Итак, да, это постоянная времени компиляции.

clang 3.4 производит аналогичный код:

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   b8 00 00 00 00          mov    eax,0x0
   9:   c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  10:   c7 45 f8 04 00 00 00    mov    DWORD PTR [rbp-0x8],0x4
  17:   5d                      pop    rbp
  18:   c3                      ret

Опять же, это постоянная времени компиляции.

Все было скомпилировано с -O0.

P.S.: Если a объявлено const, то для gcc ничего не меняется, но для clang does, значение 4 не движется напрямую, как если бы была константа времени компиляции.

Если a не объявлено ни const, ни constexpr, то оба компилятора не могут обрабатывать Parameters:: v [0] как константу времени компиляции.