2

I have C++ code that maps GUID(unsigned long) to structure.

#include <string>
#include <map>
#include <iostream>

typedef unsigned long GUID;

enum Function {
  ADDER = 1,
  SUBTRACTOR = 2,
  MULTIPLIER = 3,
  SQUAREROOT = 4
};

struct PluginInfo
{
    GUID guid;
    std::string name;
    Function function;

    PluginInfo(GUID _guid, std::string _name, Function _function) {guid = _guid, name = _name, function = _function;}
};

typedef std::map<GUID, PluginInfo> PluginDB;

PluginInfo temp1(1, "Adder", ADDER);
PluginInfo temp2(2, "Multiplier", MULTIPLIER);

PluginDB::value_type pluginDbArray[] = {
    PluginDB::value_type(1, temp1),
    PluginDB::value_type(2, temp2)
};

const int numElems = sizeof pluginDbArray / sizeof pluginDbArray[0];
PluginDB pluginDB(pluginDbArray, pluginDbArray + numElems);

int main()
{
    std::cout << pluginDB[1].name << std::endl;
}

When I compile it, I got error message.

/usr/include/c++/4.2.1/bits/stl_map.h: In member function ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = long unsigned int, _Tp = PluginInfo, _Compare = std::less, _Alloc = std::allocator >]’: mockup_api.cpp:58: instantiated from here /usr/include/c++/4.2.1/bits/stl_map.h:350: error: no matching function for call to ‘PluginInfo::PluginInfo()’ mockup_api.cpp:29: note: candidates are: PluginInfo::PluginInfo(GUID, std::string, Function) mockup_api.cpp:24: note:
PluginInfo::PluginInfo(const PluginInfo&)

What might be wrong?

prosseek
  • 182,215
  • 215
  • 566
  • 871

2 Answers2

3

Any objects you place in a STL container initialized with an initial number of objects (i.e., you're not initializing an empty container) must have at least one default constructor ... yours does not. In other words your current constructor needs to be initialized with specific objects. There must be one default constructor that is like:

PluginInfo();

Requiring no initializers. Alternatively, they can be default initializers like:

PluginInfo(GUID _guid = GUID(), 
           std::string _name = std::string(), 
           Function _function = Function()): 
           guid(_guid), name(_name), function(_function) {}
Jason
  • 31,834
  • 7
  • 59
  • 78
  • If you mean that they must have a default constructor, this is wrong. STL containers can certainly contain objects that do not have default constructors. The requirement is that they be copyable and assignable. –  Apr 18 '11 at 20:34
  • No, sorry, didn't explicitly mean that ... I've tried to modify my answer to correct that assumption and show you can have alternate constructors, but they must be something that can be initialized without having to pass in any explicit parameters by the user. – Jason Apr 18 '11 at 20:37
  • @Jason Such a constructor is a default constructor - and your answer is still wrong. –  Apr 18 '11 at 20:38
  • So you can create a constructor for an object that requires explicit user-passed parameters (no default initializers), and store that object in an STL container? Isn't that the error that the compiler is throwing? – Jason Apr 18 '11 at 20:41
  • @Jason Yes, otherwise storing things like BankAccount (which can have no sensible defaults) in STL containers would not be possible. As to what the problem with the OP's code is - I couldn't say, as soon as I see a use of sizeof in C++ code my brain turns off and I feel no need to turn it back on again in this case. –  Apr 18 '11 at 20:44
  • Okay, I see what you're saying, but for instance, code like this: http://ideone.com/lKnvU fails when you try to create an STL container that is intialized with a pre-defined size, and there is no default constructor (and you do not pass the code a specific object to create multiple instances of). I've updated the answer again to reflect this. – Jason Apr 18 '11 at 20:54
  • @Jason Yes, if you need to create a sized container (very rare in my experience) then you must either have a default constructor (which is any constructor that takes no parameters after default parameters are considered) or provide some functor (or similar) which will construct the objects. But as I said, this is very unusual. –  Apr 18 '11 at 21:03
3

The problem is that when you say:

 pluginDB[1]

you try to create an entry in the map (because [1] does not exist) and to do that as Jason points out, you need a default constructor. However, this is NOT a general requirement of standard library containers, only of std::map, and only of operator[] for std::map (and multimap etc.), which is a good reason why IMHO operator[] for maps et al should be done away with - it is far too confusing for new C++ programmers, and useless for experienced ones.