How to create std :: map of constant values ​​which are still accessible to the operator []?

I need a std: map data structure that is only readable, which means that I have to fill it with data once, and then read only these values, do not change them or add additional ones.

My non-const version looks like this:

//in .h #include <string> #include <map> std::map<std::string, int> myMap; void initMap(); //in .cpp #include "foo.h" void initMap() { myMap["Keys"] = 42; } 

Then I would call initMap() once in my code and do it.

Now I have read several questions here, and for the map it seems nontrivial to achieve a constant.

To do this std::map<std::string, const int> will not allow filling it in initMap() . Filling it with a non-constant temp, and the copy constructor by definition, does not work either, since the copy constructor does not just accept the non-constant version as input.

Creating const std::map<std::string, int> (which I could fill with a non-constant copy during the definition) will disable the use of the [] operator to access the values.

So, is there a way to achieve (value) a constant and initialize the structure (preferably in the header file)?

BTW: neither C ++ 0x, nor C ++ 11, nor boost:: are parameters.

+6
source share
5 answers

Can't use the insert() method for std::map ?

http://www.cplusplus.com/reference/map/map/insert/

Edit: (solution) myMap.insert(std::pair<std::string, const int>("Keys", 42));

As I understand it, the reason for this is that the constructor for the pair pair (const first_type& a, const second_type& b) initializes its first and second members with the constructors for first_type and second_type , taking a and b as their corresponding parameter.

With the solution you tried to use, I understand that myMap["Keys"] = 42; initializes the second map member (of type const int ) using the default constructor for int . Then this element is assigned a value. Since this is done outside the constructor of the map class, declaring const makes this impossible.

Using a solution using insert() , members are initialized in the pair constructor. That way they can be declared const . The same operation is performed when pair copied to map .

+13
source

While this is not possible for you, others who want to do this and who have a C ++ 11 compatible compiler can use uniform initialization :

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

Oh, and by the way, don't define the map in the header file. Instead, declare it as extern in the header file, then define it in the source file.

+8
source

The easiest solution is to write your own, wrap a standard map class:

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

You can initialize a map by passing it to iterators in a sequence of everything that can be converted to value_type .

Depending on your needs, you can add additional forwarding typedefs, functions, etc. If you are using C ++ 11, you may also want to create a constructor that can use an initializer list.

+2
source

If map cannot mutate, you should use const map<string, int> , not map<string, const int> : the second version allows you to insert and delete objects.

Unfortunately, you have to lose the [] operator; C ++ does not have an ImmutableMap , or something like that. However, std::map::at and std::map::find not so bad ...

+1
source

Something much simpler that is smaller and faster :

  static const int MyMapData [] = {
     42 // index 0 is mapped to "key"
 };

struct MyMap {const int & operator [] (std :: string) const {switch (key) {case "Keys": return MyMapData [0];

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

};

Easy to maintain, lack of use of templates, use of enhancement libraries and compilation everywhere.

0
source

Source: https://habr.com/ru/post/945660/


All Articles