Как инициализировать карту массивов разных размеров?

Простой вопрос, как инициализировать карту массивов (или другого типа контейнера) разных размеров? Например:

enum class code {A,B,C};
enum class res {X1,X2,X3,X4,X5};

std::map<code, ?> name {
    {code:A, {res::X1,res::X2}},
    {code:B, {res::X2,res::X3, res::X4}},
    {code:C, {res::X5}}

};

Мне нужно найти во время компиляции, если res::X2 в карте name в code::B

Это выражение должно, я думаю, проверить это с помощью static_assert:

constexpr bool validate(code t, res p, int i = 0) {
    return (name[t][i] == p ? true : ((sizeof(name[t]) == (i+1)) ? false :validate(t, p, ++i)));
}

Так как validate это constexpr базовый массив будет работать, но как определить его в аргументе карты как массив типа res? И чтобы каждый массив мог быть разным по размеру?

Итак, я сделал ошибку. У меня сложилось впечатление, что к карте можно получить доступ в функции constexpr. Какой тип контейнера вы можете мне предложить, чтобы я мог достичь того, что я написал выше?

3 ответа

Решение

Поскольку std::map не может быть использован в constexpr Выражение Я был вынужден найти другое решение, и благодаря @kfsone и @H. Guijt за указание на это, а также упоминание std::initializer_list а также std::array что привело меня к этому решению.

Поскольку данные на карте в вопросе будут постоянными, я могу обойтись без ассоциативного контейнера. Поэтому я использовал отсортированный массив std::initializer_listвместе с constexpr реализация функции поиска, которая отлично подходит для моих нужд.

template <class It, class T>
inline constexpr It sfind (It begin, It end, T const& value) noexcept
{
    return ! (begin != end && *begin != value)? begin : sfind (begin+1, end, value);
}

enum class code {A,B,C};
enum class res {X1,X2,X3,X4,X5};

constexpr std::array<std::initializer_list<res>, 3> name {{
    {res::X1,res::X2}, //code::A
    {res::X2,res::X3, res::X4}, //code::B
    {res::X5} // code::C

}};
const code c = code::A;
const res r = res::X3;
static_assert (name[static_cast<int>(c)].end () - sfind(name[static_cast<int>(c)].begin(), name[static_cast<int>(c)].end(), r) != 0,"Not found");

Если для массива все в порядке, это работает:

std::map<code, std::initializer_list<res>> name {
    {code::A, {res::X1,res::X2}},
    {code::B, {res::X2,res::X3, res::X4}},
    {code::C, {res::X5}}
};

Если вам нужно иметь возможность записи в массив, вам нужно что-то вроде этого:

std::map<code, std::vector<res>> name {
    {code::A, {res::X1,res::X2}},
    {code::B, {res::X2,res::X3, res::X4}},
    {code::C, {res::X5}}
};

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

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

std::map<code, std::array<res, 3>> name {
    {code::A, {res::X1,res::X2}},
    {code::B, {res::X2,res::X3, res::X4}},
    {code::C, {res::X5}}
};

Что касается второй части вашего вопроса, я не совсем уверен, сработает ли какое-либо решение, учитывая, что вы не можете получить доступ к карте в функции constexpr.

Вы не можете использовать std::map в выражении constexpr, не в последнюю очередь потому, что он имеет нетривиальный деструктор (~map(); указано в стандарте).

Если вы ищете map раздел стандарта для constexpr, вы его не найдете ( http://eel.is/c++draft/map), а для std::array ( http://eel.is/c++draft/array.syn)

Другие вопросы по тегам