如何初始化不同大小数组的映射?
How to initialize a map of arrays of different sizes?
简单的问题,如何初始化不同大小的数组(或其他一些容器类型)的映射?例如:
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
基本数组可以工作,但是如何在 map 参数中将其定义为 res
类型的数组?而且每个数组的大小可能不同?
所以,我犯了一个错误。我的印象是 map 可以在 constexpr 函数中访问。您可以建议我使用哪种容器类型来实现我上面写的内容?
如果数组是 const 没问题,这行得通:
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 函数中访问地图,我不太确定 any 解决方案是否有效。
您 不能 在 constexpr 表达式中使用 std::map
,尤其是因为它有一个非平凡的析构函数(~map();
在标准)。
如果您搜索 constexpr 标准的 map
部分,您将找不到它 (http://eel.is/c++draft/map), whereas you will for std::array
(http://eel.is/c++draft/array.syn)
因为 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");
简单的问题,如何初始化不同大小的数组(或其他一些容器类型)的映射?例如:
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
基本数组可以工作,但是如何在 map 参数中将其定义为 res
类型的数组?而且每个数组的大小可能不同?
所以,我犯了一个错误。我的印象是 map 可以在 constexpr 函数中访问。您可以建议我使用哪种容器类型来实现我上面写的内容?
如果数组是 const 没问题,这行得通:
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 函数中访问地图,我不太确定 any 解决方案是否有效。
您 不能 在 constexpr 表达式中使用 std::map
,尤其是因为它有一个非平凡的析构函数(~map();
在标准)。
如果您搜索 constexpr 标准的 map
部分,您将找不到它 (http://eel.is/c++draft/map), whereas you will for std::array
(http://eel.is/c++draft/array.syn)
因为 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");