Во время создания экземпляра класса: «no operator» [] «сопоставляет эти операнды» при доступе к значению std :: map с помощью map [key] - PullRequest
0 голосов
/ 07 апреля 2020

Я давно смотрю на это. Я не понимаю, что беспокоит это. Минимальный код, который дает мне проблему, показан ниже. Я комментирую строку, где происходит ошибка. После кода следуют ошибки компиляции.

#include <map>
#include <cstdlib>
#include <cstdint>

template<std::size_t D>
class myclassA{
private:  
  std::array<std::string, D> a;
  std::map<std::string, std::size_t> a_type_num;
  std::array<std::size_t, D> a_dims;

  // used to initialize a_type_num
  inline std::map<std::string, std::size_t> return_type_dims() const{
    std::map<std::string, std::size_t> temp;
    for(auto const &s: a)
      temp.emplace(s, 0);
    for(auto const &s: a)     
      temp[s]++;
    return temp;
  };

  // used to initialize a_dims
  inline std::array<std::size_t, D> return_site_dims() const{
    std::array<std::size_t, D> temp;
    for(int i=0; i<D; i++)
      temp[i] = a_type_num[a[i]];  // ERROR!!!
    return temp;
  };

public:  
  // constructor
  myclassA(const std::array<std::string,D> &user) :  a(user)
    , a_type_num(return_type_dims())
    , a_dims(return_site_dims())
  {};
};

int main(int argc, char *argv[]){
  myclassA<4> co({"d","d","p","p"});
  return 0;
}

При компиляции я получаю ошибку:

src/main.cpp(32): error: no operator "[]" matches these operands
            operand types are: const std::map<std::__cxx11::string, std::size_t, std::less<std::__cxx11::string>, std::allocator<std::pair<const std::__cxx11::string, std::size_t>>> [ const std::__cxx11::string ]
        temp[i] = a_type_num[a[i]];  
                            ^
          detected during:
            instantiation of "std::array<std::size_t={unsigned long}, D> myclassA<D>::return_site_dims() const [with D=4UL]" at line 40
            instantiation of "myclassA<D>::myclassA(const std::array<std::__cxx11::string, D> &) [with D=4UL]" at line 45

С другой стороны, что-то вроде этого компилируется нормально (я имею в виду, что код собирается ничего не делать, но он компилируется):

#include <map>
#include <cstdlib>
#include <cstdint>

int main(int argc, char *argv[]){
  // myclassA<4> co({"d","d","p","p"});

  std::array<std::string, 10> a;
  std::map<std::string, std::size_t> a_type_num;
  std::array<std::size_t, 10> temp;
  for(int i=0; i<10; i++)
    temp[i] = a_type_num[a[i]];  

return 0;

Итак, мой вопрос: почему он жалуется, что no operator "[]" matches these operands?

Ответы [ 3 ]

2 голосов
/ 07 апреля 2020

return_site_dims() объявлен как метод const, поэтому его указатель this равен const myclassA*, и, следовательно, элемент a_type_num, доступ к которому осуществляется через этот указатель, обрабатывается как объект const std::map. Однако std::map не имеет operator[], который может быть вызван для объекта const std::map, следовательно, ошибка компилятора. operator[] карты вставляет новую запись, если запрошенный ключ не найден, и ее нельзя вставить в const std::map объект.

Вы можете использовать at() карты. вместо этого метод с перегрузкой const, который не вставляет отсутствующие ключи, вместо этого выдает std::out_of_range исключения:

inline std::array<std::size_t, D> return_site_dims() const{
  std::array<std::size_t, D> temp;
  for(int i=0; i<D; i++)
    temp[i] = a_type_num.at(a[i]); // <-- OK! exception if a[i] is not found...
  return temp;
};

В качестве альтернативы, вы можете использовать find() карты метод вместо:

inline std::array<std::size_t, D> return_site_dims() const{
  std::array<std::size_t, D> temp;
  for(int i=0; i<D; i++) {
    auto iter = a_type_num.find(a[i]);
    if (iter != a_type_num.end())
      temp[i] = iter->second;
    else
      temp[i] = ...; // <-- some default value of your choosing...
  }
  return temp;
};
2 голосов
/ 07 апреля 2020

Оператору [] требуется std::map, который не является const, потому что его поведение, когда он не находит ключ, состоит в изменении карты путем вставки ключа. В вашем коде у вас есть метод return_site_dims, который является методом const, что означает, что он имеет только const доступ ко всем не * stati c членам класса myClassA, включая a_type_num карта. Поэтому этот метод не может использовать оператор [] на этой карте. Чтобы это исправить, вы можете сделать return_site_dims не const метод.

1 голос
/ 07 апреля 2020

Причина, по которой он не может работать, заключается в том, что return_site_dims объявлен как const, но operator[] не является методом const (он изменит карту, если элемент не найден). Единственный способ получить доступ к const std::map - использовать std::map::find или std::map::at, если вы хотите получить исключение вместо ручной обработки. Таким образом, ваш l oop может быть переписан:

// used to initialize a_dims
std::array<std::size_t, D> return_site_dims() const {
  std::array<std::size_t, D> temp;
  decltype(a_type_num.end()) iter, iter_end = a_type_num.end();
  for (int i=0; i<D; i++) {
    iter = a_type_num.find(a[i]);
    if (iter == iter_end) {
      // HANDLE THIS SOMEHOW
    }
    temp[i] = *iter;
  }
  return temp;
}

Дополнительный комментарий: вам не нужно объявлять inline функции inline, поскольку функции, записанные в объявлении класса, автоматически становятся такими.

...