1

Consider the following example:

enum class DOG_TYPE {SHEPHARD, COLLIE,UNKNOWN};

static  const std::map<std::string,DOG_TYPE> dogMap = {
                {"GS",DOG_TYPE::SHEPHARD}
};


DOG_TYPE getDogType(const std::string& dogtype) 
{
    if(dogMap.find(dogtype) != dogMap.end())
    {
        return  dogMap[dogtype];  -->Does not work when std::map is constant
    }
}

int main()
{
DOG_TYPE j = getDogType("GS");
std::cout << int(j);
}

In the above example the statement return dogMap[dogtype]; returns the error

error: passing 'const std::map<std::__cxx11::basic_string<char>, DOG_TYPE>' as 'this' argument discards qualifiers [-fpermissive]
         return  dogMap[dogtype];

I would like to know why this happens and why cant map be const static ?

James Franco
  • 4,516
  • 10
  • 38
  • 80

3 Answers3

7

Using operator[] on a std::map creates the object if it doesn't exist. So it's an operation that can only be performed on a map you are allowed to modify. Use find instead.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
5

It doesn't work because std::map does not have an operator[] that is declared as const, so you can't use operator[] on a const std::map object.

std::map::operator[] is defined to return a reference to a keyed value. If the key is not found, the map is modified to insert a default value for the key so it can then bind the returned reference. Obviously, modifying a const std::map cannot work, hence the compiler error.

To do what you are attempting, you can use std::map::find() to search for the key without inserting a new value for it. If the key is found, you can dereference the returned iterator.

Don't forget to have your function return a default value if the key is not found.

Try this:

DOG_TYPE getDogType(const std::string &dogtype) 
{
    auto iter = dogMap.find(dogtype);
    if (iter != dogMap.end())
        return iter->second;
    return DOG_TYPE::UNKNOWN;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

As said by other, operator[] modify the map if the key isn't present.

But you can use at()

DOG_TYPE getDogType(const std::string& dogtype) 
{
    if(dogMap.find(dogtype) != dogMap.end())
    {
        return  dogMap.at(dogtype);
    }
}

And, if you can afford that getDogType() throws an exception when dogtype isn't a key in dogMap, simply

DOG_TYPE getDogType(const std::string& dogtype) 
{
        return  dogMap.at(dogtype);
}

p.s.: at() available only from C++11

p.s.2: sorry for my bad English.

max66
  • 65,235
  • 10
  • 71
  • 111
  • Using `find()` and `at()` together is redundant since you would be performing 2 identical searches to get 1 result. Use *either* `find()` *or* `at()`, not *both*. – Remy Lebeau Aug 05 '16 at 07:02
  • @RemyLebeau - you're right: my first example is ineffective (and the second questionable because throw an exception when the OP could want `UNKNOWN` instead of an exception). As an excuse I say that my intention was only show to the OP that `operator[]` it's present only in non-const mode when `at()` is present (from C++11) with a const version. – max66 Aug 05 '16 at 21:54