Reputation: 247
Here is the approximate code of my question. First, we have a struct with a constructor:
struct Pair{
Pair(int a, int b): (first (a) , second (b) ) {}
int first;
int second;
};
which is used in a map
map<string, Pair> mymap;
I would like to initialize this map in a function
void f(map<string, Pair>* mymap, string c,int x, int y )
{
(*mymap)[c]=Pair(x,y);
}
But the compiler says first that it could not find an appropriate constructor and then the next lines are that not enough arguments are provided for the constructor.
A friend of mine told me that I should write the function like this:
void f(map<string, Pair>& mymap, const string& c,int x, int y )
{
if (mymap.find(c) != mymap.end()) {
mymap[c] = Pair(x,y);
}
}
But he could not explain why Type& should be used here instead of Type *, and I would like to clarify this point. Can anybody explain?
Upvotes: 1
Views: 222
Reputation: 227558
You will need a default contrructor:
Pair(): first () , second () {}
This is needed for the map's operator[]
, which creates a default-constructed mapped_type
when called with a non-existent key-
and a less-than operator that implements strict weak ordering:
struct Pair {
// as before
bool operator<(const Pair& rhs) const {
/ some code to implement less-than
}
};
or you can pass a comparison functor or function implementinf strict weak ordering as a third template argument.
Upvotes: 2
Reputation: 208446
The problem is that operator[]
in a map requires that the value type is default constructible. If you don't want your Pair
to be default constructible, you will have to avoid using operator[]
:
void f(map<string, Pair>& mymap, string c,int x, int y )
{
mymap.insert( std::make_pair(c,Pair(x,y)) );
}
You may have misunderstood what your friend suggested. The problem with operator[]
is not that it requires the default constructor if it needs to create a new element, but that it requires it in case it might need to. That is, whether the element exists before hand or not does not really matter.
If you also mean to update, then you need to consider also that option:
void f(map<string, Pair>& mymap, string c,int x, int y )
{
auto res = mymap.insert( std::make_pair(c,Pair(x,y)) );
if ( !res.second )
res.first->second = Pair(x,y);
}
Basically the insert
operation returns a pair of the iterator pointing at the key and a bool indicating if this insert
created the object or if it was already there (in which case the value in the map is unmodified). By storing the result, we can test and if the insert
did not create the value, we can update it through the returned iterator.
Upvotes: 3
Reputation: 59841
Calling operator[]
on map will require your type to be default constructible. You can avoid that by using map::insert or map::emplace
Upvotes: 2
Reputation: 308520
The standard containers need a default constructor. They will use the operator=
to set the correct value at some point after construction.
Upvotes: 0