g ++ и clang ++ различное поведение с рекурсивной инициализацией статического члена - PullRequest
0 голосов
/ 04 марта 2019

Учитывая следующий код:

#include <iostream>

template <std::size_t N>
struct foo
 { static std::size_t value; };

template <>
std::size_t foo<0>::value = 0u;

template <size_t N>
std::size_t foo<N>::value = 1u + foo<N - 1u>::value;

int main()
 {
   std::cout
      << foo<3u>::value << ' '
      << foo<2u>::value << ' '
      << foo<1u>::value << ' '
      << foo<0u>::value << std::endl;
 }

, где статический член value структуры шаблона foo рекурсивно инициализирован, я получаю различные выходные данные из g ++:

3 2 1 0

и из clang ++:

1 1 1 0

Похоже, что g ++ рекурсивно инициализирует foo<N>::value, используя инициализированное значение foo<N-1u>::value, где clang ++ использует ноль для foo<N-1u>::value.

Два вопроса:

  1. является ли предыдущий код допустимым или это каким-то образом неопределенное поведение?
  2. если предыдущий код является допустимым, кто прав: g ++ или clang ++?? 1022 *

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

Это Не указано .

Вы используете конструкцию , где вы ссылаетесь на определение переменной на себя - возможно, в некоторой степени аналогично высказыванию int i = i-1.В случае clang, он просто использует общее определение шаблона

template <std::size_t N>
struct foo
  { static std::size_t value; };//without specialization this will be ZERO initialized

, потому что он не видел «себя», как обычный шаблонный класс или функция (в отличие от случая gcc).

Для суммирования:

1) Legit

2) Unspecified

Чтобы избежать проблем, используйте и специализируйте классшаблон вместо.

0 голосов
/ 04 марта 2019

Не указано.Оба компилятора правы.

Вот соответствующие фрагменты из cppreference "initialization" .

Статическая инициализация

Для всех остальныхлокальные статические и локальные переменные потока, инициализация нуля происходит

Таким образом, для всех этих переменных они равны нулю при загрузке программы.Затем:

Динамическая инициализация

После завершения всей статической инициализации динамическая инициализация нелокальных переменных происходит в следующих ситуациях:

1) Неупорядоченная динамическая инициализация, которая применяется только к (статическим / локальным для потока) членам статических данных шаблона класса и ... которые не являются явно специализированными.

И эти переменные соответствуют критериям.И тогда он говорит:

Инициализация таких статических переменных неопределенно упорядочена относительно всех других динамических инициализаций ....

Что означает, что любая последовательность инициализациихорошо.Оба компилятора верны.

Чтобы избежать этой проблемы, используйте constexpr вместо принудительной "постоянной инициализации".

...