Как инициализировать поле std :: array внутри структуры содержимым контейнера последовательности переменной длины? - PullRequest
1 голос
/ 18 марта 2020

У меня есть структура, которая в очень упрощенном представлении выглядит следующим образом:

struct Flags {
    const std::array<unsigned int, 8> flags;

    Flags(std::vector<unsigned int> initialFlagValues) : flags(initialFlagValues) {}
};

, которая, конечно, не компилируется. Для целей моей программы я хотел бы инициализировать произвольное количество элементов в flags, в зависимости от длины параметра (std::vector, C -стиль массива или иным образом), переданного в конструктор struct.

Теперь я хотел бы использовать std::array внутри структуры, так как сама структура создается много раз (поэтому std::vector не будет идеальным здесь из-за большого количества распределений / освобождений) , но количество значений в flags, которые необходимо инициализировать, не всегда одинаково.

Есть ли способ инициализировать указанное c количество полей в flags в зависимости от размера контейнера последовательности, переданного в качестве параметра в конструктор?

Ответы [ 4 ]

3 голосов
/ 18 марта 2020

Используйте вспомогательную функцию, возможно, в форме лямбды:

Flags(std::vector<unsigned int> initialFlagValues) :
    flags([](const auto& init) {
             std::array<unsigned int, 8> flags;
             // bounds check omitted for brevity
             std::copy(init.begin(), init.end(), flags.begin());
             return flags;
         }(initialFlagValues))
{}
2 голосов
/ 18 марта 2020

Может быть, вспомогательная функция может быть делегированным конструктором

struct Flags
 {
   std::array<unsigned int, 8u> const flagsArr;

   template <std::size_t ... Is>
   Flags (std::vector<unsigned int> iFV, std::index_sequence<Is...>)
      : flagsArr{ Is < iFV.size() ? iFV[Is] : 0u ... }
    {}

   Flags (std::vector<unsigned int> iFV)
      : Flags{iFV, std::make_index_sequence<8u>{}}
    {}
};

Вы можете обобщить с помощью для обобщенных c типов, поддерживающих операторы [] и std::size() (так же как массивы C -тиля) следующим образом

struct Flags
 {
   std::array<unsigned int, 8u> const flagsArr;

   template <typename T, std::size_t ... Is>
   Flags (T const & iFV, std::index_sequence<Is...>)
      : flagsArr{ Is < std::size(iFV) ? iFV[Is] : 0u ... }
    {}

   template <typename T>
   Flags (T const & iFV)
      : Flags{iFV, std::make_index_sequence<8u>{}}
    {}
};
1 голос
/ 18 марта 2020

Вы также можете делать все во время (почти) компиляции, без итераций:

#include <iostream>
#include <type_traits>
#include <iterator>

struct Omg {
        static constexpr std::size_t SIZE = 8;

        template<class Container> Omg(Container &&c)
                : Omg(std::forward<Container>(c), std::make_index_sequence<SIZE>{})
        {}

        void omg() const {
                for(auto i: array) std::cout << i << ' ';
                std::cout << '\n';
        }
private:
        template<class C, std::size_t... is> Omg(C &&c, std::index_sequence<is...>)
                : array{get<is>(std::forward<C>(c))...}
        {}

        template<std::size_t i, class C> static constexpr auto get(C &&c) {
                return i < std::size(c)? c[i] : 0;
        }

        std::array<int, SIZE> array;
};

int main() {
        Omg(std::vector<int>{0, 1, 2, 3}).omg();
        int nyan[] = {42, 28, 14};
        Omg(nyan).omg();
}
1 голос
/ 18 марта 2020

std::array - совокупность. Это означает, что единственный способ инициализировать его - braced_init_list ({}). Невозможно преобразовать std::vector в braced_init_list , поэтому вы можете использовать al oop внутри конструктора, например

Flags(std::vector<unsigned int> initialFlagValues) : flags{} // zero out flags
{
    auto size = std::min(initialFlagValues.size(), flags.size())
    for (size_t i = 0; i < size; ++i)
        flags[i] = initialFlagValues[i];
}

. Это будет означать, что flags быть неконстантным. Если это изменение вы не можете сделать, то вам нужно будет сделать initialFlagValues a std::array или использовать вспомогательную функцию для возврата массива, который вы можете использовать для инициализации flags с помощью.

...