Скомпилирован ли совершенно новый класс для каждого std::array разного размера?

Насколько я понимаю, шаблонирование c++ работает путем компиляции отдельного класса или функции для каждого необходимого типа. Это кажется логичным для классов или функций, которые будут вызываться только для нескольких различных типов/параметров, но для std::array кажется, что это может привести к тому, что один и тот же класс будет скомпилирован в сотни разных версий.

Я понимаю преимущества std::array перед массивами в стиле C, но кажется, что использование первого приведет к огромным двоичным размерам по сравнению с последним, если мое предположение верное.

Например, если, скажем, в большой программе мы в конечном итоге используем 99 массивов разных размеров во всем коде, так что мы эффективно имеем:

int arr[1]   = { ... }
int arr[2]   = { ... }
int arr[...] = { ... }
int arr[99]  = { ... }
int arr[100] = { ... }

Или

 std::array<int, 1> arr   = { ... }
 std::array<int, 2> arr   = { ... }
 std::array<int, ...> arr = { ... }
 std::array<int, 99>  arr = { ... }
 std::array<int, 100> arr = { ... }

Приведет ли пример std::array к тому, что весь класс и все его функции будут скомпилированы в двоичный файл 99 раз?

Ответы

Ответ 1

Да, новый класс создается шаблоном класса для каждого отдельного набора параметров шаблона.

Но этот класс не обязательно должен существовать в двоичном коде среды выполнения.

Большинство методов короткие, и их следует указывать при использовании. Поэтому они не будут выбрасываться в двоичный файл.

Если вы начнете брать адреса методов и сохранять их, вы начнете раздувать, поскольку вы заставляете каждый отдельный метод существовать.

Например, двоичный генератор раздувания:

template<std::size_t...Ns>
std::function<std::type_info const&()> stupid(std::size_t i, std::index_sequence<Ns...>) {
  std::function<std::type_info const&()> retval;
  (
    ((i || (retval = []()->std::type_info const&{
       return typeid( std::array<int, Ns> );
    })) && i--) && ...
  );
  return retval;
}
std::function<std::type_info const&()> stupid( std::size_t i ) {
  return stupid( i, std::make_index_sequence<100>{} );
}

это требует, чтобы библиотека содержала информацию rtti для 100 различных std::array с.

Но если вы не делаете такого рода вещи, RTTI не нужен. Так что это не вводится в ваш двоичный файл.

И я могу сделать то же самое с 100 различными массивами.

template<std::size_t...Ns>
std::function<std::type_info const&()> stupid(std::size_t i, std::index_sequence<Ns...>) {
  std::function<std::type_info const&()> retval;
  (
    ((i || (retval = []()->std::type_info const&{
       return typeid( int[Ns] );
    })) && i--) && ...
  );
  return retval;
}
std::function<std::type_info const&()> stupid( std::size_t i ) {
  return stupid( i, std::make_index_sequence<100>{} );
}

"класс" в C++ не такой уж тяжелый предмет, как в других языках ОО. Нет глобального состояния класса, если вы не заставите его существовать.

Ответ 2

  Приведет ли пример std::array к тому, что весь класс и все его функции будут скомпилированы в двоичный файл 99 раз?

Нет, у вас действительно есть один экземпляр класса для каждого параметра...

Но это не будет включать в себя все методы. Будет создан только экземплярный метод.

В вашем случае вы просто используете агрегатную инициализацию, поэтому она идентична.

Ответ 3

Да, std::array<int,1> будет скомпилирован в другой класс, чем std::array<int,2>.

Но не волнуйся. поскольку std::array - это просто тонкая оболочка вокруг массивов c- (int arr[2]), большинство методов в любом случае будут встроены.

в некотором смысле, std::array<int,1>::operator[] и std::array<int,2>::operator[] будут скомпилированы в два разных метода, но эти два метода будут скомпилированы в одни и те же инструкции процессора и будут встроены в функцию вызова, когда оптимизация включена.

Ответ 4

Да, каждая специализация класса будет создаваться для разных аргументов шаблона.

Создание экземпляров специализации класса не приводит к автоматическому созданию определений его функций-членов. Только их декларации создаются. Это не влияет на двоичный код, пока не будут использованы функции.