0

我已经看了很长时间了。我不明白是什么在困扰它。给我问题的最小代码如下所示。我评论发生错误的行。编译错误跟在代码后面。

#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呢?

4

3 回答 3

2

[]运算符需要一个std::mapthat is not const,因为它在找不到键时的行为是通过插入键来修改映射。在您的代码中,您拥有的return_site_dims方法是一个const方法,这意味着它只能const访问该类的所有非静态成员myClassA,包括a_type_num地图。因此,此方法无法[]在该地图上使用运算符。要解决此问题,您可以创建return_site_dims一个非const方法。

于 2020-04-07T00:36:07.513 回答
2

return_site_dims()被声明为const方法,因此它的this指针是const myclassA*,因此a_type_num通过该指针访问的成员被视为const std::map对象。但是,std::map没有operator[]可以在const std::map对象上调用的,因此编译器错误。如果找不到请求的键,则映射会operator[]插入一个新条目,并且它不能插入到const std::map对象中。

您可以改用 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;
};
于 2020-04-07T00:37:59.123 回答
1

它无法工作的原因return_site_dims是声明为const,但operator[]不是const方法(如果找不到元素,它将修改映射)。访问 a 的唯一方法const std::map是使用std::map::find或者std::map::at如果您想要异常而不是手动处理。所以你的循环可以重写:

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

旁注:您不需要声明inlinefunctions inline,因为在类声明中编写的函数会自动如此。

于 2020-04-07T00:40:48.393 回答