Как инициализировать карту массивов разных размеров?
Простой вопрос, как инициализировать карту массивов (или другого типа контейнера) разных размеров? Например:
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)