Мне интересно, есть ли правильный способ сделать это.
Учитывая пример:
struct Test {
static std::array<unsigned, 123> data;
};
std::array<unsigned, 123> Test::data = {};
Если я хочу установить для всех элементов в data
какое-то значение, например, 5.
Я мог бы сделать что-то вроде этого:
struct Test {
static std::array<unsigned, 123> data;
private:
static decltype(data) init_data_arr() {
decltype(data) arr = {};
arr.fill(5);
return arr;
}
};
std::array<unsigned, 123> Test::data = Test::init_data_arr();
Но тогда я бы выделил дополнительные массивы памяти и сделал бы копию всего этого, что не кажется идеальным.
Другим менее интенсивным вариантом памяти будет что-то вроде:
struct Test {
static bool is_init;
static std::array<unsigned, 123> data;
Test() {
if (!is_init) {
is_init = true;
data.fill(5);
}
}
};
bool Test::is_init = false;
std::array<unsigned, 123> Test::data = {};
Но теперь у меня есть дополнительные накладные расходы при построении моей тестовой структуры.
Теперь я знаю, что вы можете инициализировать массивы pod следующим образом: std::array<int, 3> a = {1, 2, 3};
но для массивов размером N
это быстро стало бы ужасно поддерживать.
Кажется, что каждое решение, с которым я сталкиваюсь, просто использует функцию-член fill
в классе массива, но всегда обрабатывает массивы так, как будто они являются нестатическими переменными-членами, или инициализирует их в основном, оба из них на самом деле не помогают моей ситуации.
Изменить: я создал этот заголовок утилиты, который обобщает второй вариант. #прагма один раз
#include <utility>
#include <iterator>
#include <algorithm>
#include <type_traits>
namespace Utils {
template<typename Container>
using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<Container&>()))>;
template<class Container>
static Container create_filled_container(const element_type_t<Container>& value) {
Container container = {};
std::fill(container.begin(), container.end(), std::move(value));
return container;
}
}
Это, вероятно, можно было бы улучшить больше, но, похоже, это работает. Использование выглядит следующим образом:
std::array<unsigned, 123> Test::data = Utils::create_filled_container<decltype(data)>(456);
который устанавливает для всех элементов все, что вы укажете.
Edit2: Итак, я провел еще несколько тестов, и похоже, что вызов функции для заполнения массива по сравнению с ручным выполнением не всегда дает одну и ту же сборку.
Я установил демо здесь!
Edit3: кое-что изменилось, чтобы это могло быть constexpr, вот его текущая форма:
template<class Container>
static constexpr Container create_filled_container(const element_type_t<Container>& value) {
Container container = {};
for (auto it = container.begin(); it != container.end(); ++it)
*it = value;
return container;
}
который производит ту же сборку сейчас.
Test::init_data_arr()
примера по сравнению с инициализацией {0, ..., n}. - person Hex Crown   schedule 20.06.2019-O3
, в зависимости от типа данных, например char/float/int, сборка, созданная функцией заполненного массива, может значительно измениться из-за подробного arr = {1, 2,3,...,n} инициализация. - person Hex Crown   schedule 20.06.2019