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?
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
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.
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) { }
Related
I am continually getting the following error message telling me that I am using a deleted function, which I think is the std::variant default constructor.
In file included from main.cpp:2:
Document.hpp: In instantiation of ‘Document<StateVariant, EventVariant, Transitions>::Document(StateVariant&&) [with StateVariant = std::variant<DraftState, PublishState>; EventVariant = std::variant<EventWrite, EventRead>; Transitions = TransitionRegister]’:
main.cpp:7:61: required from here
Document.hpp:33:37: error: use of deleted function ‘std::variant<_Types>::variant() [with _Types = {DraftState, PublishState}]’
33 | Document(StateVariant &&a_state) {
| ^
In file included from Document.hpp:6,
from main.cpp:2:
/usr/include/c++/11/variant:1385:7: note: ‘std::variant<_Types>::variant() [with _Types = {DraftState, PublishState}]’ is implicitly deleted because the default definition would be ill-formed:
1385 | variant() = default;
| ^~~~~~~
/usr/include/c++/11/variant:1385:7: error: use of deleted function ‘constexpr std::_Enable_default_constructor<false, _Tag>::_Enable_default_constructor() [with _Tag = std::variant<DraftState, PublishState>]’
In file included from /usr/include/c++/11/variant:38,
from Document.hpp:6,
from main.cpp:2:
/usr/include/c++/11/bits/enable_special_members.h:112:15: note: declared here
112 | constexpr _Enable_default_constructor() noexcept = delete;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
The code is roughly:
#include <iostream>
#include <variant>
class DraftState {
public:
DraftState() = default; // default constructor
DraftState(const DraftState &a_state) { m_msg = a_state.m_msg; } // copy constructor
DraftState(const std::string &a_rMsg = "") { m_msg = a_rMsg; } // custom constructor
DraftState(DraftState &&a_state) { m_msg = std::move(a_state.m_msg);} // move constructor
DraftState& operator=(DraftState &&a_state) { if(this != &a_state) { m_msg = std::move(a_state.m_msg); } return *this; } // move assignable constructor
~DraftState() = default; // destructor
std::string getState() { return "DraftState"; }
std::string m_msg;
};
class PublishState{
// similar to DraftState
};
using State = std::variant<DraftState, PublishState>;
template<typename StateVariant>
class Document
{
public:
Document() = default;
Document(StateVariant &&a_state) {
m_state = std::move(a_state);
}
StateVariant m_state;
//...
};
int main()
{
DraftState draftState("draft");
Document<State> doc(draftState);
return 0;
}
I have tried adding a default constructor call in the custom constructor Document(StateVariant &&a_state)'s initializer list but that does not seem to work either. Any help understanding this cryptic message is appreciated thanks. Sorry for the long code.
While you do need to work on a minimal example, the core problem is your DraftState default constructor is ambiguous with your string constructor with a default argument. See https://godbolt.org/z/hTnsjoWaW
To be default constructible, std::variant requires the first type argument to be default constructible. The ambiguity causes the compiler to think your class is not default constructible, and therefore neither is the variant.
Also, your move constructor for Document should use the member initializer list, rather than assignment. And your DraftState is missing the copy assignment operator, though unless there's more to it, I wouldn't explicitly define all of the copy/move/destructor values. See the Rule of Five.
I failed to understand the steps of compilation of this code.
First, where is what is purpose of the default constructor, and why so many objects of type MyClass?
link to sololearn where I saved the code
#include <iostream>
using namespace std;
class MyClass {
public:
int var;
MyClass() { }
MyClass(int a)
: var(a) { }
MyClass operator+(MyClass &obj) {
MyClass res;
res.var= this->var+obj.var;
//'this' is refering to active (obj1)
return res;
}
};
int main() {
MyClass obj1(12), obj2(55);
MyClass res = obj1+obj2;
cout << res.var;
}
//I've not understood, its from a lesson
If you suspect you don't need a piece of code, try compiling without it and you'll know pretty quickly whether your suspicion was correct or not.
When you remove the default constructor in the class you provided here's what happens:
..\Playground\: In member function 'MyClass MyClass::operator+(MyClass&)':
..\Playground\:11:21: error: no matching function for call to 'MyClass::MyClass()'
MyClass res;
^~~
..\Playground\:7:9: note: candidate: MyClass::MyClass(int)
MyClass(int a)
^~~~~~~
..\Playground\:7:9: note: candidate expects 1 argument, 0 provided
..\Playground\:4:7: note: candidate: constexpr MyClass::MyClass(const MyClass&)
class MyClass {
Which is to say the problem is in the +operator implementation at the line MyClass res; . This line creates an instance of the object MyClassusing the default constructor, so there's no way the code snippet your provided works without a default constructor.
The constructor without parameters is for the object that doesn't pass any value, the one that stores the sum of the two operand objects. ---simple---
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?
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
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.
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) { }
I have coded a very basic class
class A
{
int n;
public:
A(int& val){val=n;}
A(const int& val=0){n=val;}
A(A& val){n=val.n;}//work without this constructor
};
int main()
{
A a=3;//want to call A::A(const int&)
return 0;
}
I don't want to create a constructor with a copy from an instance of A (for a future use)
What's wrong with this simple code?
Error message :
...\main.cpp||In function 'int main()':|
...\main.cpp|16|error: no matching function for call to 'A::A(A)'|
...\main.cpp|16|note: candidates are:|
...\main.cpp|11|note: A::A(A&)|
...\main.cpp|11|note: no known conversion for argument 1 from 'A' to 'A&'|
...\main.cpp|10|note: A::A(const int&)|
...\main.cpp|10|note: no known conversion for argument 1 from 'A' to 'const int&'|
...\main.cpp|9|note: A::A(int&)|
...\main.cpp|9|note: no known conversion for argument 1 from 'A' to 'int&'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
It seems 3 is considered as an instance of A?
If I add A(const A& val){n=val.n;}
the constructor A(const int&) is chosen.
What can I do to compile successfully without A(const A& val)?
The issue is your copy constructor: A(A& val) { n=val.n; }.
Given this line A a = 3; one possibility is to use A a = A(3) which in turn will use the copy constructor. However, it is against the standard to bind a temporary to non-const. A proper copy constructor will solve the problem.
Example Code
#include <iostream>
class A
{
int n;
public:
A(int& val) : n(val) { std::cout << "A(int&)\n"; }
A(const int& val=0) : n(val) { std::cout << "A(const int&)\n"; }
A(const A& val) : n(val.n) { std::cout << "A(const A&)\n"; }
};
int main()
{
A a = 3;
return 0;
}
Example Output
A(const int&)
Live Example
Note:
The above code makes proper use of the initialization lists
The output shows the copy constructor is not actually invoked
The line of code;
A a = 3;
Is using copy initialisation to work. For that to work, a copy of A is needed and is duly made. You have two constructors taking an int as an argument (and neither are explicit).
The copy cannot bind to A(A& val) because normal references don't bind to temporary values.
Possible solutions, direct initialisation;
A a { 3 };
Add or change the copy constructor to a move constructor;
A(A&& val);
Add a const to the copy constructor (although this is not what you wanted, but it does work);
A(A const& val);
Note both clang and g++ reject the original code correctly, but VC++ accepts it.
In this statement
A a=3;//want to call A::A(const int&)
there is created a temporary object of type A using constructor
A(const int& val=0){n=val;}
However a temporary object can be bound to a constant reference. So the compiler need that the copy constructor
A( const A& val){n=val.n;}//work without this constructor
^^^^^
would be at least accessible (even if it will not be called due to the copy constructor elision).
But the class does not has this constructor and the compiler issues an error.
On the other hand when you comment this constructor then the compiler itself implicitly defines this constructor and the code is compiled.
Take into account that this constructor
A(int& val){val=n;}
^^^^^^
does not make sense.:)
The test is as following:
class NotInit{};
NotInit NOT_INIT;
template<class T>
class Optional{
T value;
bool has_value;
public:
Optional() : value(), has_value(false){}
explicit Optional(NotInit):value(), has_value(false) {}
explicit Optional(T const & val):value(val), has_value(true){}
explicit Optional(Optional<T> const & other) {}
Optional& operator=(Optional<T> const & other){}
Optional& operator=(T const & other){}
};
enum X {
FIRST
};
struct Some {
Optional<X> member;
};
int main(int, char**){
Optional<X> const opt(NOT_INIT);
Some s = {NOT_INIT};
return 0;
}
Clang 3.4 complains:
../st.cpp:31:12: error: no viable conversion from 'NotInit' to 'Optional<X>'
Some s = {NOT_INIT};
^~~~~~~~
1 error generated.
Why does it complain for the struct initialization but ont for the varaiable? Why is it not choosing the constructor with the proper parameter?
What overload is missing so that i can use this to init the struct?
I cannot use boost and i'm not sure this error would not appear if using boost::optional.
You are marking your constructors explicit. Thus when you are trying to initialize your struct Some with a brace-initializer list, you are triggering an implicit conversion...
This is prevented here:
class NotInit;
template <typename T>
class Optional {
// Here => Optional(NotInit) cannot be called implicitly
explicit Optional(NotInit):value(), has_value(false) {}
};
/* ... */
Some s = {NOT_INIT}; // Implicit call to Optional<X>(NotInit): whoops!
If you remove the explicit, you can keep:
Some s = {NOT_INIT};
If you chose not to, then you'll have to instantiate s like this:
Some s = {Optional<X>(NOT_INIT)};
In any case, you'll have to remove the explicit keyword on your copy constructor (which has to perform a copy and not be a "dummy" constructor).
Why? Because once the Optional<X> object is built from NOT_INIT, a copy has to be made to s.member.
Note: You could also provide a move constructor, which would be more appropriate in that case, since the object you get from the conversion of NOT_INITis an rvalue.