如何创建一个仍然可以被[]运算符访问的常量值的std :: map?

时间:2013-05-23 08:01:47

标签: c++ dictionary stl const c++03

我需要一个只读的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::

5 个答案:

答案 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}的构造函数初始化其成员firstsecond {}}和first_type,将second_typea作为各自的参数。

使用您尝试使用的解决方案,我的理解是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::atstd::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库,并且随处可编译。