Reputation: 123
I have been looking at this for quite some time. I don't understand what is bothering it. The minimum code that is giving me the problem is shown bellow. I comment on the line where the error occurs. Compilation errors follow after the code.
#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;
}
When compiling I get the error:
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
On the other hand, something like this compiles fine (I mean the code is going to do nothing, but it compiles):
#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;
So my question is: why is it complaining that no operator "[]" matches these operands
?
Upvotes: 1
Views: 1127
Reputation: 598134
return_site_dims()
is declared as a const
method, so its this
pointer is const myclassA*
, and thus the a_type_num
member accessed via that pointer is treated as a const std::map
object. However, std::map
does not have an operator[]
that can be called on a const std::map
object, hence the compiler error. A map's operator[]
inserts a new entry if the requested key is not found, and it can't insert into a const std::map
object.
You can use the map's at()
method instead, which has a const
overload that does not insert missing keys, it throws std::out_of_range
exceptions instead:
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;
};
Alternatively, you can use the map's find()
method instead:
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;
};
Upvotes: 2
Reputation: 738
The reason that it cannot work is that return_site_dims
is declared as const
, but operator[]
is not a const
method (it will modify the map if the element is not found). The only way to access a const std::map
is using std::map::find
or std::map::at
if you want to have an exception instead of manual handling. So your loop could be rewritten:
// 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;
}
Side comment: You don't need to declare inline
functions inline
, since functions written in the class declaration are automatically so.
Upvotes: 2
Reputation: 119562
The []
operator requires a std::map
that is not const
, because its behaviour when it does not find the key is to modify the map by inserting the key. In your code, you have the return_site_dims
method which is a const
method, meaning that it only has const
access to all the non-static members of the myClassA
class, including the a_type_num
map. Therefore, this method is not able to use the []
operator on that map. To fix this, you could make return_site_dims
a non-const
method.
Upvotes: 3