Константная ссылка в цикле на основе диапазона не работает

Я думал, что вы можете использовать ссылку на константу в циклах на основе диапазона в C++ 11, но когда я компилирую этот код с помощью g++:

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

int main() {
    std::vector<std::unordered_map<std::string, int> > coordinates {
        {{"x", 50}, {"y", 50}},
        {{"x", 25}, {"y", 75}},
        {{"x", 326}, {"y", 412}},
    };
    for(const auto& i : coordinates) {
        std::cout << "{\"x\" : " << i["x"] << ", \"y\" : " << i["y"] << "}\n";
    }
}

Я получаю эту ошибку:

const_error.cc:13:38: error: no viable overloaded operator[] for type 'const
      std::__1::unordered_map<std::__1::basic_string<char>, int,
      std::__1::hash<std::__1::basic_string<char> >,
      std::__1::equal_to<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      int> > >'
        std::cout << "{\"x\" : " << i["x"] << ", \"y\" : " << i["y"] << "}\n";
                                    ~^~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:1131:18: note: 
      candidate function not viable: 'this' argument has type 'const
      std::__1::unordered_map<std::__1::basic_string<char>, int,
      std::__1::hash<std::__1::basic_string<char> >,
      std::__1::equal_to<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      int> > >', but method is not marked const
    mapped_type& operator[](const key_type& __k);
                 ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:1133:18: note: 
      candidate function not viable: 'this' argument has type 'const
      std::__1::unordered_map<std::__1::basic_string<char>, int,
      std::__1::hash<std::__1::basic_string<char> >,
      std::__1::equal_to<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      int> > >', but method is not marked const
    mapped_type& operator[](key_type&& __k);
                 ^
const_error.cc:13:64: error: no viable overloaded operator[] for type 'const
      std::__1::unordered_map<std::__1::basic_string<char>, int,
      std::__1::hash<std::__1::basic_string<char> >,
      std::__1::equal_to<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      int> > >'
        std::cout << "{\"x\" : " << i["x"] << ", \"y\" : " << i["y"] << "}\n";
                                                              ~^~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:1131:18: note: 
      candidate function not viable: 'this' argument has type 'const
      std::__1::unordered_map<std::__1::basic_string<char>, int,
      std::__1::hash<std::__1::basic_string<char> >,
      std::__1::equal_to<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      int> > >', but method is not marked const
    mapped_type& operator[](const key_type& __k);
                 ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:1133:18: note: 
      candidate function not viable: 'this' argument has type 'const
      std::__1::unordered_map<std::__1::basic_string<char>, int,
      std::__1::hash<std::__1::basic_string<char> >,
      std::__1::equal_to<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      int> > >', but method is not marked const
    mapped_type& operator[](key_type&& __k);
                 ^

Но когда я удаляю const из цикла for на основе диапазона, он работает нормально. Почему мой код не скомпилируется со ссылкой на const?


person PointerToConstantChar    schedule 26.04.2017    source источник
comment
Эта проблема не имеет ничего общего с циклами for. Вы могли бы сузить это гораздо больше.   -  person Kerrek SB    schedule 26.04.2017


Ответы (2)


operator[] не константа. Если ключ не существует, он добавляет объект значения к этому ключу.

Вместо этого используйте unordered_map::at.

person Yochai Timmer    schedule 26.04.2017

Оператор [] для map и unordered_map требует вызова для неконстантного объекта, потому что он обновит объект, чтобы вставить новую запись, если она не существует для этого ключа.

Что вы хотите, чтобы произошло, например, если "x" нет на карте?

  • Создать новую запись? Тогда вы не сможете использовать const.
  • Генерировать ошибку времени выполнения? Затем используйте find или другую функцию, которая просматривает карту, не изменяя ее, вместо [].
person M.M    schedule 26.04.2017