8

我需要一个只读的 std:map 数据结构,这意味着我必须用数据填充一次,然后只读取这些值,永远不要更改它们或添加其他值。

我的非常量版本如下所示:

//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()在我的代码中调用一次并完成。

现在我已经在这里阅读了几个问题,并且为地图实现 const-ness 似乎并非易事。

将其设为 astd::map<std::string, const int>将不允许我将其填写在initMap(). 用非常量临时填充它并且定义上的复制构造函数也不起作用,因为复制构造函数不容易将非常量版本作为输入。

使其成为const std::map<std::string, int>(我可以在定义期间填充非常量副本)将禁用[]运算符用于值访问。

那么有没有办法实现(值)const-ness并初始化结构(最好在头文件中)?

顺便说一句:C++0x 和 C++11 都不boost::是一个选项。

4

5 回答 5

15

你不能使用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)初始化了它的成员first,并second使用了 and 的构造函数first_typesecond_type并将aandb作为它们各自的参数。

对于您尝试使用的解决方案,我的理解是使用默认构造函数myMap["Keys"] = 42;初始化(类型)second的成员。然后尝试为该成员分配一个值。由于这是在 class 的构造函数之外完成的,因此声明使这不可能。mapconst intintmapconst

通过使用 的解决方案insert(),成员在 的构造函数中被初始化pair。因此可以声明它们constpair将复制到时执行相同的操作map

于 2013-05-23T08:28:57.150 回答
9

虽然这对您来说是不可能的,但其他想要这样做并且拥有 C++11 兼容编译器的人可以使用统一初始化

std::map<std::string, const int> myMap = {
    { "keys", 42 }
};

哦,顺便说一句,不要在头文件中定义映射。而是在头文件中声明它,然后在源文件中定义它。extern

于 2013-05-23T08:08:27.960 回答
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.

根据您的需要,您可能需要添加额外的转发类型定义、函数等。如果您使用的是 C++11,您可能还需要创建一个可以使用列表初始值设定项的构造函数。

于 2013-05-23T08:38:03.970 回答
1

如果map不能变异,你应该使用const map<string, int>, 而不是map<string, const int>:第二个版本允许插入和删除对象。

可悲的是,您将不得不失去[]操作员;C++ 没有ImmutableMap, 或类似的东西。然而,std::map::atstd::map::find不算太糟糕......

于 2013-05-23T08:09:23.743 回答
0

更简单的东西,占用空间更小,速度更快

静态常量 int MyMapData[] = {
    42 // 索引 0 映射到“key”
};

结构 MyMap { const int& operator[](std::string key) const { 开关(键){ 案例“键”:返回 MyMapData[0];

default: return NotANumber; // Return 0 and raise an assertion, or return "Not a Number". } }

};

易于维护,不使用模板,不使用 boost 库并且可以在任何地方编译。

于 2016-08-16T08:44:12.560 回答