1

I'm writing a C++ application in which I have a Controller class with two nested structs, defined in my header file as follows:

class Controller {
    struct help_message {   // controller.hpp, line 19
        std::string summary;
        std::string details;
        help_message(const std::string&, const std::string&);
    };

    struct player_command {
        cmd_t cmd;
        help_message help;
        // cmd_t is my own typedef, irrelevant for this question
        player_command(const cmd_t&, const help_message&);
    };

    // more members...
};

In my source file, I have this:

Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) {
    cmd = c;
    help = h;
};

Controller::help_message::help_message(const std::string& s, const std::string& d) {
    summary = s;
    details = d;
};

which I thought was fine, but when I compile, this is what I get (controller.cpp line 12 is the first line of the source snippet above):

g++  -g -Wall -std=c++0x  -c -o controller.o controller.cpp
controller.cpp: In constructor ‘palla::Controller::player_command::player_command(void (palla::Controller::* const&)(const args_t&), const palla::Controller::help_message&)’:
controller.cpp:12:93: error: no matching function for call to ‘palla::Controller::help_message::help_message()’
controller.cpp:12:93: note: candidates are:
In file included from controller.cpp:7:0:
controller.hpp:22:3: note: palla::Controller::help_message::help_message(const string&, const string&)
controller.hpp:22:3: note:   candidate expects 2 arguments, 0 provided
controller.hpp:19:9: note: palla::Controller::help_message::help_message(const palla::Controller::help_message&)
controller.hpp:19:9: note:   candidate expects 1 argument, 0 provided
controller.hpp:19:9: note: palla::Controller::help_message::help_message(palla::Controller::help_message&&)
controller.hpp:19:9: note:   candidate expects 1 argument, 0 provided
make: *** [controller.o] Error 1

From what I can deduce, the compiler is somewhere trying to call the default constructor of help_message, which doesn't exist. It then tries to match the call up with the constructor I created as well as with the generated copy-constructor and assignment operator, and failing each on the number of arguments.

But what part of my code is calling a default constructor? And how do I fix this error?

Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • 1
    Already answered well, but to put it another way: Every constructor first constructs all subobjects *before* entering the body in `{}` marks. If you don't say how, it will try default constructors. So you might as well say how using a mem-initializer-list. – aschepler Jan 08 '13 at 16:20

3 Answers3

7

The player_command() constructor first default constructs help and then assigns to it:

Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) {
    cmd = c;
    help = h;
};

Change that to:

Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h)
:  cmd(c),
   help(h)
{
};

See Benefits of Initialization lists

Community
  • 1
  • 1
NPE
  • 486,780
  • 108
  • 951
  • 1,012
3

The player_command struct contains a help_message (help), and there is no default constructor for help_message. When the player_command constructor is called, by default the help member variable will be default constructed. You are immediately assigning help to the given parameter but this will be after it is default constructed. Instead change the constructor to be something like:

Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) : cmd(c), help(h) 
{}

This will invoke the copy constructor for both cmd and help member variables instead of doing default construction and then assignment.

Nathan Buckles
  • 221
  • 1
  • 5
0

You are not using the syntax which avoids the copy constructor. The argument is passed by reference (no copy constructor) but it is indeed copied when assigned to the ivar.

Class::Class(const Variable &var) {
  this->var = var; // assignment here, this invokes copy contructor!
}

You should use the following syntax:

Class::Class(const Variable &var) : var(var) { }
Jack
  • 131,802
  • 30
  • 241
  • 343