我需要一个只读的std:map数据结构,这意味着我必须用数据填充一次,然后只读取这些值,永远不要更改它们或添加其他值。
我的非const版本看起来像这样:
//in .h
#include <string>
#include <map>
std::map<std::string, int> myMap;
void initMap();
//in .cpp
#include "foo.h"
void initMap() {
myMap["Keys"] = 42;
}
然后我会在代码中调用initMap()
一次并完成。
现在我已经在这里阅读了几个问题,实现地图的常数似乎并非易事。
将其设为std::map<std::string, const int>
将不允许我填写initMap()
。
使用非const temp填充它并且定义上的复制构造函数也不起作用,因为复制构造函数不容易将非const版本作为输入。
将其设为const std::map<std::string, int>
(我可以在定义期间填充非常量副本)将禁止使用[]
运算符进行值访问。
那么有没有办法实现(值)const-ness并初始化结构(最好是在头文件中)?
BTW:既不是C ++ 0x也不是C ++ 11,也不是boost::
。
答案 0 :(得分:13)
您无法使用insert()
可用的std::map
方法吗?
http://www.cplusplus.com/reference/map/map/insert/
编辑:(解决方案)myMap.insert(std::pair<std::string, const int>("Keys", 42));
据我所知,其工作原因是因为该对的构造函数pair (const first_type& a, const second_type& b)
使用{{1}的构造函数初始化其成员first
和second
{}}和first_type
,将second_type
和a
作为各自的参数。
使用您尝试使用的解决方案,我的理解是b
使用默认构造函数初始化myMap["Keys"] = 42;
(类型second
)的成员map
const int
。然后尝试将值分配给该成员。由于这是在类int
的构造函数之外完成的,因此map
声明使这变得不可能。
使用const
的解决方案,成员在insert()
的构造函数中初始化。因此可以声明它们pair
。将const
复制到pair
时会执行相同的操作。
答案 1 :(得分:9)
虽然这对您来说是不可能的,但是其他想要执行此操作且具有C ++ 11兼容编译器的人可以使用uniform initialization:
std::map<std::string, const int> myMap = {
{ "keys", 42 }
};
哦顺便说一下,不要在头文件中定义地图。而是在头文件中将其声明为extern
,然后在源文件中定义它。
答案 2 :(得分:2)
最简单的解决方案是编写自己的,包装 标准地图类:
template <typename KeyType, typename MappedType, typename CmpType>
class ConstantMap
{
typedef std::map<KeyType, MappedType, CmpType> Impl;
Impl myImpl;
public:
typedef Impl::value_type value_type;
template <ForwardIterator>
ConstantMap( ForwardIterator begin, ForwardIterator end, CmpType cmp = CmpType() )
: myImpl( begin, end, cmp )
{
}
// necessary if [] is not going to work for missing keys
bool contains( KeyType const& key ) const
{
return myImpl.find( key ) != myImpl.end();
}
MappedType const& operator[]( KeyType const& key ) const
{
Impl::const_iterator elem = myImpl.find( key );
if ( elem == myImpl.end() ) {
// Not found, do what you want (maybe throw an exception)
}
return elem.second;
}
};
您可以通过将迭代器传递给序列来初始化地图
任何可以转换为value_type
的内容。
根据您的需要,您可能需要添加其他内容 转发typedef,函数等。如果你正在使用C ++ 11,那么你 可能还想创建一个可以使用列表的构造函数 初始化程序。
答案 3 :(得分:1)
如果map
无法变异,则应使用const map<string, int>
,而不是map<string, const int>
:第二个版本允许插入和删除对象。
可悲的是,你将不得不失去[]
运营商; C ++没有ImmutableMap
或类似的东西。但是,std::map::at
和std::map::find
并不太糟糕......
答案 4 :(得分:0)
更简单的东西,更小的足迹,更快:
static const int MyMapData[] = { 42 // index 0 is mapped to "key" };struct MyMap { const int& operator[](std::string key) const { switch (key) { case "Keys": return MyMapData[0];
GetByIds()
};
易于维护,不使用模板,不使用boost库,并且随处可编译。