如何初始化不同大小的数组映射?

时间:2016-08-01 15:28:26

标签: c++ arrays dictionary constexpr static-assert

简单的问题,如何初始化不同大小的数组(或其他容器类型)的映射?例如:

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)));
}

因为validateconstexpr基本数组可行,但如何在map参数中将其定义为res类型的数组?并且每个阵列的大小可能不同?

所以,我犯了一个错误。我的印象是可以在constexpr函数中访问地图。您可以建议我使用哪种容器类型来实现我上面所写的内容?

3 个答案:

答案 0 :(得分:1)

如果数组可以是常量,则可以正常工作:

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函数中的地图。

答案 1 :(得分:0)

不能在constexpr表达式中使用std::map,尤其是因为它有一个非平凡的析构函数(标准中指定的~map();)。

如果您搜索constexpr标准的map部分,则无法找到它(http://eel.is/c++draft/map),而您将std::arrayhttp://eel.is/c++draft/array.syn)< / p>

答案 2 :(得分:0)

由于std::map无法在constexpr表达式中使用,因此我被迫寻找另一种解决方案,感谢@kfsone和@H。 Guijt指出了这一点,并提到引导我解决这个问题的std::initializer_liststd::array

由于问题中地图中的数据是常量,我可以不使用关联容器。因此,我使用了std::initializer_list s的排序数组以及查找函数的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");