Let's say I have this dummy class definition:
class Node
{
public:
Node ();
Node (const int = 0);
int getVal();
private:
int val;
};
And dummy constructor implementations for educational purposes only as well:
Node::Node () : val(-1)
{
cout << "Node:: DEFAULT CONSTRUCTOR" << endl;
}
Node::Node(const int v) : val(v)
{
cout << "Node:: CONV CONSTRUCTOR val=" << v << endl;
}
Now, if I compile (with options: -Wall -Weffc++ -std=c++11) the code below:
#include <iostream>
#include "node.h"
using namespace std;
int main()
{
Node n;
return 0;
}
I get this error, and does not compile at all:
node_client.CPP: In function ‘int main()’:
node_client.CPP:10:16: error: call of overloaded ‘Node()’ is ambiguous
Node n;
^
node_client.CPP:10:16: note: candidates are:
In file included from node_client.CPP:4:0:
node.h:14:5: note: Node::Node(int)
Node (const int = 0);
^
node.h:13:2: note: Node::Node()
Node ();
^
I cannot understand why.
As far as I know (I am learning C++), a call to Node::Node() should not be ambiguous with respect to Node::Node(const int) because the have a different parameter signature.
There is something I am missing: What it is?
a call to Node::Node() should not be ambiguous with respect to Node::Node(const int) because the have a different parameter signature.
Sure that is ambiguous. Think twice!
You have
Node ();
Node (const int = 0);
which one should be selected when you call Node()?? The one with the defaulted value parameter?
It should work without providing the default:
Node ();
Node (const int); // <<<<<<<<<<<<< No default
The compiler just cannot know if you want to call the default constructor or the int constructor with a default value.
You have to remove the default value or remove the default constructor (which does the same thing as your constructor with int so that's not really a problem!)
Related
Here's the code I have:
#include <iostream>
#include <functional>
struct Test {
struct Envelope {
const int x = 1;
int y = 2;
int z = 3;
};
Envelope mEnvelope;
struct Buffer {
Envelope mEnvelope;
} mBuffer;
std::function<Buffer()> func{[this] {
mBuffer.mEnvelope = mEnvelope;
return mBuffer;
}};
};
int main() {
Test test;
}
it says:
g++ -std=c++17 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In lambda function:
main.cpp:17:29: error: use of deleted function 'Test::Envelope& Test::Envelope::operator=(const Test::Envelope&)'
17 | mBuffer.mEnvelope = mEnvelope;
| ^~~~~~~~~
main.cpp:5:12: note: 'Test::Envelope& Test::Envelope::operator=(const Test::Envelope&)' is implicitly deleted because the default definition would be ill-formed:
5 | struct Envelope {
| ^~~~~~~~
main.cpp:5:12: error: non-static const member 'const int Test::Envelope::x', can't use default assignment operator
I've tried using a Copy Constructor:
Envelope(const Envelope &other) {
y = other.y;
}
or override the operator =
Envelope &operator=(Envelope &other) {
// self-assignment guard
if (this == &other) {
return *this;
}
y = other.y;
}
But the errors grown even more.
I need to copy only some "part" of the object.
This is just a test, of course the real object have lots of members fields, and some need to be ignored.
How to do it within a std::function<Buffer()>?
OK, since it might not be obvious what the problem is:
A copy assignment operator should usually have a const& parameter, not a & parameter.
You should then also provide the copy constructor of Envelope as you showed. First of all it has different behavior than the implicitly-generated one (which would copy over all the elements, not only y) and the generation of the implicit copy constructor when there is a user-defined copy assignment has been deprecated since C++11 and will probably be removed in a future standard iteration.
Then you will need to default the default constructor as well, since you have a user-defined constructor now:
Envelope() = default;
Furthermore, your copy assignment operator is declared to return a Envelope& (as it should), but you forgot to actually put a return statement in it at its end, so executing it will cause undefined behavior as is:
return *this;
You can create your own copy ctor/operator in order to only copy the info you want:
#include <iostream>
#include <functional>
struct Test {
typedef struct {
const int x;
int y;
int z;
} Envelope_t;
public:
Test():env({1,2,3}){}
Test(const Test & copy):env({copy.env.x,5,copy.env.z}) {}
Test& operator=(const Test& copy){
env.y=copy.env.y+7;
env.z=copy.env.z;
return *this;
}
void printValues() {
std::cout << "x:" << env.x << "\ny:" <<
env.y << "\nz:" << env.z << "\n\n";
}
private:
Envelope_t env;
};
int main() {
Test original;
original.printValues();
Test copyCtor(original);
copyCtor.printValues();
Test copyOp;
copyOp = copyCtor;
copyOp.printValues();
}
In the following code, I construct an instance of Node by passing an instance of Point. e.g. Node{{0, 1}}; However, the call to Node's constructor is ambiguous. My guess it that {0, 1} can also be comprehended as two int representations of char, and {char, char} also applies to the constructor of std::string, in the form of std::initializer_list<char>.
I want to preserve the ability to construct Node conviniently as Node{{0, 1}} while also retain the conversion from std::string to Node, preferebly in the form of Node{std::string{"0,1"}} or something like that. Is there a way to call the constructor that takes a string only if I specifies it to do so? or simply disable the std::string's constructor of std::initializer_list<char>?
Thanks in adavance.
#include <string>
class Point
{
public:
Point() {};
Point(int x, int y) : x(x), y(y) {}
private:
int x;
int y;
};
class Node
{
public:
Node(const std::string& str) {}
Node(const Point& dot) : dot(dot) {}
private:
Point dot;
};
int main()
{
Node{{0, 1}};
return 0;
}
Error Message:
/Users/cpp_sandbox.cpp:24:5: error: call to constructor of 'Node' is ambiguous
Node{{0, 1}};
^ ~~~~~~~~
/Users/cpp_sandbox.cpp:16:5: note: candidate constructor
Node(const std::string& str) {}
^
/Users/cpp_sandbox.cpp:17:5: note: candidate constructor
Node(const Point& dot) : dot(dot) {}
^
1 error generated.
[Finished in 0.1s with exit code 1]
[shell_cmd: g++ -std=c++11 "/Users/cpp_sandbox.cpp" -o "/Users/cpp_sandbox"]
[dir: /Users]
[path: /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/X11/bin:/Applications/SquishCoco/:/Library/TeX/texbin]
As mentioned in the comments, you're out of luck with your current code as both constructors are viable candidates. A solution is to use inheritance instead of aggregation and have Node derive from Point. You must also explicitly inherit Point's constructor:
class Node: public Point
{
public:
using Point::Point; // constructor inheritance
Node(std::string str) {}
};
Now you can use
Node{0, 1}; // note that Node{{0, 1}} will invoke the string ctor
and
Node{"test"};
just fine.
Full example:
#include <iostream>
#include <string>
class Point
{
public:
Point() {};
Point(int x, int y) : x(x), y(y) {std::cout << __PRETTY_FUNCTION__ << '\n';}
private:
int x{};
int y{};
};
class Node: public Point
{
public:
using Point::Point;
Node(const std::string&) {std::cout << __PRETTY_FUNCTION__ << '\n';}
};
int main()
{
Node{0, 1};
Node{"test"};
}
Live on Coliru
If you wonder why now Node{{0, 1}} will invoke the Node::Node(const std::string&) constructor instead of an ambiguity, that's because the only viable constructor candidate is Node::Node(const std::string&) (the other inherited constructor has the signature Point::Point(int, int), so it won't accept an initializer list). Whereas in your original code Node::Node(const Point&) would also be a viable constructor due to the implicit conversion from an initializer list to a Point (this kind of constructor is called a conversion constructor).
Question:
Is there a difference between the following initializations?
(A) What exactly is the second one doing?
(B) Is one more efficient than the other?
int variable = 0;
int variable = int();
This question also applies to other data types such as std::string:
std::string variable = "";
std::string variable = std::string();
Background:
I basically got the idea here (the second code sample for the accepted answer) when I was trying to empty out a stringstream.
I also had to start using it when I began learning classes and realized that member variable initializations had to be done in the constructor, not just following its definition in the header. For example, initializing a vector:
// Header.h
class myClass
{
private:
std::vector<std::string> myVector;
};
// Source.cpp
myClass::myClass()
{
for (int i=0;i<5;i++)
{
myVector.push_back(std::string());
}
}
Any clarity on this will be greatly appreciated!
Edit
After reading again, I realized that you explicitely asked about the default constructor while I provided a lot of examples with a 1 parameter constructor.
For Visual Studio C++ compiler, the following code only executes the default constructor, but if the copy constructor is defined explicit, it still complains because the never called copy constructor can't be called this way.
#include <iostream>
class MyInt {
public:
MyInt() : _i(0) {
std::cout << "default" << std::endl;
}
MyInt(const MyInt& other) : _i(other._i) {
std::cout << "copy" << std::endl;
}
int _i;
};
int main() {
MyInt i = MyInt();
return i._i;
}
Original (typo fixed)
For int variables, there is no difference between the forms.
Custom classes with a 1 argument constructor also accept assignment initialization, unless the constructor is marked as explicit, then the constructor call Type varname(argument) is required and assignment produces a compiler error.
See below examples for the different variants
class MyInt1 {
public:
MyInt1(int i) : _i(i) { }
int _i;
};
class MyInt2 {
public:
explicit MyInt2(int i) : _i(i) { }
int _i;
};
class MyInt3 {
public:
explicit MyInt3(int i) : _i(i) { }
explicit MyInt3(const MyInt3& other) : _i(other._i) { }
int _i;
};
int main() {
MyInt1 i1_1(0); // int constructor called
MyInt1 i1_2 = 0; // int constructor called
MyInt2 i2_1(0); // int constructor called
MyInt2 i2_2 = 0; // int constructor explicit - ERROR!
MyInt2 i2_3 = MyInt2(0); // int constructor called
MyInt3 i3_1(0); // int constructor called
MyInt3 i3_2 = 0; // int constructor explicit - ERROR!
MyInt3 i3_3 = MyInt3(0); // int constructor called, copy constructor explicit - ERROR!
}
The main difference between something like:
int i = int(); and int i = 0;
is that using a default constructor such as int() or string(), etc., unless overloaded/overridden, will set the variable equal to NULL, while just about all other forms of instantiation and declarations of variables will require some form of value assignment and therefore will not be NULL but a specific value.
As far as my knowledge on efficiency, neither one is "better".
I have this code in C++:
#include <iostream>
class Object
{
public:
Object();
Object(int someValue = 0);
private:
int value;
};
Object::Object()
{
std::cout << "No argument constructor" << std::endl;
value = 0;
}
Object::Object(int someValue)
{
std::cout << "Argument constructor" << std::endl;
value = someValue
}
int main()
{
Object obj1; // should call Object() (according to me)
Object obj2(5); // should call Object(int) (according to me)
}
But the compiler (MinGW 4.8.1) on Windows 7 64 bit, complains about a call of overloaded 'Object()' being ambiguous:
defaultConstructorTest.cpp: In function 'int main()':
defaultConstructorTest.cpp:27:9: error: call of overloaded 'Object()' is ambiguous
Object obj1;
^
defaultConstructorTest.cpp:27:9: note: candidates are:
defaultConstructorTest.cpp:19:1: note: Object::Object(int)
Object::Object(int someValue)
^
defaultConstructorTest.cpp:13:1: note: Object::Object()
Object::Object()
^
So ideally, I would like to get this output:
No argument constructor
Argument constructor
This is because call to
Object obj1;
is ambiguous. As second constructor has one default argument which makes it a good enough contender for default construction of objects.
I am trying to understand how default constructor (provided by the compiler if you do not write one) versus your own default constructor works.
So for example I wrote this simple class:
class A
{
private:
int x;
public:
A() { std::cout << "Default constructor called for A\n"; }
A(int x)
{
std::cout << "Argument constructor called for A\n";
this->x = x;
}
};
int main (int argc, char const *argv[])
{
A m;
A p(0);
A n();
return 0;
}
The output is :
Default constructor called for A
Argument constructor called for A
So for the last one there is another constructor called and my question is which one and which type does n have in this case?
A n();
declares a function, named n, that takes no arguments and returns an A.
Since it is a declaration, no code is invoked/executed (especially no constructor).
After that declaration, you might write something like
A myA = n();
This would compile. But it would not link! Because there is no definition of the function n.
A n();
could be parsed as an object definition with an empty initializer or a function declaration.
The language standard specifies that the ambiguity is always resolved in favour of the function declaration (§8.5.8).
So n is a function without arguments returning an A.
For the last one NO constructor gets called.
For that matter no code even gets generated. All you're doing is telling (declaring) the compiler that there's a function n which returns A and takes no argument.
No there is not a different constructor.
A n();
is treated as a declaration of function taking no arguments and returning A object. You can see this with this code:
class A
{
public:
int x;
public:
A(){ std::cout << "Default constructor called for A\n";}
A(int x){
std::cout << "Argument constructor called for A\n";
this->x = x;
}
};
int main(int argc, char const *argv[])
{
A m;
A p(0);
A n();
n.x =3;
return 0;
}
The error is:
main.cpp:129: error: request for member ‘x’ in ‘n’, which is of non-class type ‘A()’