6

I'm getting the error:

error: no matching function for call to 'A::A()'
note: candidates are: A::A(const A&)
note:                 A::A(const std::string&, size_t)

From this:

#include <map>
#include <string>

using std::map;
using std::string;

class A {
public:
    string path;
    size_t size;
    A (const string& p, size_t s) : path(p), size(s) { }
    A (const A& f) : path(f.path), size(f.size) { }
    A& operator=(const A& rhs) {
        path = rhs.path;
        size = rhs.size;
        return *this;
    }
};

int main(int argc, char **argv)
{
    map<string, A> mymap;

    A a("world", 1);
    mymap["hello"] = a;      // <----- here
    A b(mymap["hello"]);     // <----- and here
}

Please tell me why the code wants a constructor with no parameters.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
William Morris
  • 3,554
  • 2
  • 23
  • 24
  • 2
    If creating a default constructor is not meaningful, use `insert` and `find`: `mymap.insert(a);` and `auto iter = mymap.find("hello"); if (iter != mymap.end()) { A b(*iter); }`. – GManNickG Jan 04 '13 at 20:21
  • Thanks. In my case it is indeed not meaningful. – William Morris Jan 04 '13 at 22:38
  • when the default constructor meaningfulness, you might want this: `auto it = mymap.insert(mymap.begin(), std::pair("hello", a));`. after that point, `it->first` is `"hello"`, and `it->second` is either `a`, if there wasn't previously an element for `"hello"`, or `it->second` is the previous element for the key `"hello"` (and `a` isn't inserted). That behaviour has the same semantics of `mymap["hello"]` if you could tell it to use the constructor you used to construct `a` instead of the default constructor. – ribamar Mar 09 '15 at 16:55

4 Answers4

7

Because map requires DefaultConstructible values, since when using subscript operator and the key is not found it adds it mapped to a default constructed value.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • 1
    More specifically, operator[] will *create* a new "default constructed" item when you attempt to add an item that does not exist then return a *reference* to that item that gets assigned whatever value you want. – Nik Bougalis Jan 04 '13 at 20:17
  • In C++11 does this still hold over the entire map? Since the requirements were put per-operation, it must be only that `operator[]` has this requirement. (`insert` would have no need for it, for example.) – GManNickG Jan 04 '13 at 20:20
  • 2
    @GManNickG: `operator[]` requires _DefaultInsertable_, not the entire map. I thought this was the case in _C++03_ as well... – K-ballo Jan 04 '13 at 20:22
  • 2
    **−1** “Because `map` requires *DefaultConstructible* values” is incorrect as of C++11 and later. – Cheers and hth. - Alf Mar 02 '16 at 01:06
4

In general a default constructor is not required for a map item value.

It was required in C++03, but that requirement was dropped in C++11, which often instead of posing container-wide requirements uses a more fine grained requirement scheme with requirements on the use of particular member functions.

The map::operator[] is one such member function, because it will create an item with the given key and a default-constructed value, if an item with the key doesn't exist.

This is also the reason why there isn't a const version of map::operator[]: it potentially modifies the map.

In C++11 and later you can use the at accessor to access an item with a given key in a const map, without the verbosity & complexity of a find.

Since map::at doesn't attempt to create an item, it doesn't require the item type to be default constructible.

And so one practical solution for your problem is to use map::at instead of map::operator[].

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Just to clarify. i actually gave it a try: If the OP would modify his last lines into: `mymap.insert(std::make_pair("hello", a));` and `A b(mymap.at("hello"));`, all would be fine. (And would compile with C++11) – Christian Oct 24 '22 at 12:21
3

mymap["hello"] can attempt to create a value-initialized A, so a default constructor is required.

If you're using a type T as a map value (and plan to access value via operator[]), it needs to be default-constructible - i.e. you need a parameter-less (default) constructor. operator[] on a map will value-initialize the mapped value if a value with the key provided is not found.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    **−1** This answer gives the impression that a `map` value needs to default constructible. That's plain wrong. So I'm downvoting even though it's written in a way so that it's technically possible for *one who knows the correct answer* to read it as not literally saying anything incorrect. – Cheers and hth. - Alf Mar 02 '16 at 01:03
  • @Cheersandhth.-Alf "and plan to access value via operator[]" seems pretty plain to me – M.M Mar 02 '16 at 01:26
  • 1
    @M.M. Because you know the correct answer. It doesn't belong in a parenthesis, it is the main and only issue. – Cheers and hth. - Alf Mar 02 '16 at 01:27
1

Long time without using C++, but If I recall correctly if you don't define a constructor for a class the compiler will create a paramless one for you. As soon as you define a constructor with parameters the compiler won't create a paramless one for you, so, you are required to create one. This added to what K-ballo exposed leads to your errors.

M.M
  • 138,810
  • 21
  • 208
  • 365
Notbad
  • 5,936
  • 12
  • 54
  • 100