Error: no matching function for call to 'A::A(A)' - c++

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.:)

Related

Differences between assignment constructor and others in C++

Consider:
std::shared_ptr<Res> ptr=new Res();
The above statement doesn't work. The compiler complains there isn't any viable conversion....
While the below works
std::shared_ptr<Res> ptr{new Res()} ;
How is it possible?!
Actually, what are the main differences in the constructor{uniform, parentheses, assignments}?
The constructor of std::shared_ptr taking a raw pointer is marked as explicit; that's why = does not allow you to invoke this constructor.
Using std::shared_ptr<Res> ptr{new Res()}; is syntax that allows you to call the an explicit constructor to initialize the variable.
std::shared_ptr<Res> ptr=new Res();
would invoke an implicit constructor taking a pointer to Res as single parameter, but not an explicit one.
Here's a simplified example using a custom class with no assignment operators and just a single constructor:
class Test
{
public:
Test(int i) { }
// mark all automatically generated constructors and assignment operators as deleted
Test(Test&&) = delete;
Test& operator=(Test&&) = delete;
};
int main()
{
Test t = 1;
}
Now change the constructor to
explicit Test(int i) { }
and the main function will no longer compile; the following alternatives would still be viable:
Test t(1);
Test t2{1};

Why rvalue reference member would be const?

I am trying to write a move constructor for a structure but I can't understand why I fail to call the move constructor of structure member:
#include <memory>
struct C
{
std::unique_ptr<int[]> mVector;
size_t mSize;
C() = default;
C(C &&temp)
: mVector(temp.mVector)
, mSize(temp.mSize)
{}
};
When I compile this I get:
gcc -c TempTest.cpp
TempTest.cpp: In constructor 'C::C(C&&)':
TempTest.cpp:9:23: error: use of deleted function 'std::unique_ptr<_Tp [], _Dp>::unique_ptr(const std::unique_ptr<_Tp [], _Dp>&) [with _Tp = int; _Dp = std::default_delete<int []>]'
9 | , mSize(temp.mSize)
| ^
In file included from c:/msys64/mingw64/include/c++/10.3.0/memory:83,
from TempTest.cpp:1:
c:/msys64/mingw64/include/c++/10.3.0/bits/unique_ptr.h:723:7: note: declared here
723 | unique_ptr(const unique_ptr&) = delete;
| ^~~~~~~~~~
Because in contructor temp is a rvalue reference, it is non-const so temp.mVector should be non-const and should call the unique_ptr move constructor but instead it calls the copy constructor which is deleted. Any idea where is the error?
Why rvalue reference member would be const?
Don't assume that it's const. You should assume that unique_ptr(const unique_ptr&) is merely the best match, from the available constructors.
Because in constructor temp is a rvalue reference
Surprise! It is not an r-value reference.
The variable temp is bound to an r-value, when the constructor is called. And now that it's a named variable, it's no longer a "temporary". It has become an l-value.
Since you know that the value was an r-value when the constructor was called, you can safely move the members, converting them back to an r-value.
C(C &&temp)
: mVector(std::move(temp.mVector))
// ^^^^^^^^^ We know that temp CAME FROM an r-value,
// so it can safely be moved.
, mSize(temp.mSize)
{}
try to run the following code and everything become clear:
struct Test
{
Test(){}
Test(const Test& r)
{
std::cout << "i am using the copy constructor :) " << std::endl;
}
Test(Test&& r)
{
std::cout << "I require std::move to be selected as possible overload.." << std::endl;
}
};
int main()
{
Test first;
Test second(first);
Test third(std::move(second));
return 0;
}
std::move helps to select the right constructor overload by passing a r-value reference (Test&&) to the constructor.
In your case, the compiler is selecting the copy constructor even if your vector isn't const, just because it is considered the best match (an implicit cast to a const reference is preferred to an implicit cast to a r-value reference, since the second one, differently from the first, may modify the value) adding a std::move you can select the right constructor and solve your issue.
#include <memory>
struct C
{
std::unique_ptr<int[]> mVector;
size_t mSize;
C() = default;
C(C &&temp)
: mVector(std::move(temp.mVector))
, mSize(temp.mSize)
{}
};

Move constructor needed, but not used, in array initialization with elements of class with deleted copy constructor

I apologize for the wordy title, but I'm having trouble concisely expressing this question.
I have a class with a deleted copy constructor and copy assignment operator. When I attempt to initialize an array with instances of the class I get a compiler error unless I provide a move constructor. However, the provided move constructor is not actually invoked.
Here's a MWE illustrating the issue.
#include <cstdio>
#include <string>
class A
{
public:
explicit A(std::string s) : s_(s) { puts("constructor"); }
A() = delete;
~A() = default;
A(const A &other) = delete;
A &operator=(const A &other) = delete;
// A(A &&other) : s_(std::move(other.s_)) { puts("move constructor"); }
void print_s() { printf("%s\n", s_.c_str()); }
private:
std::string s_;
};
int main()
{
A arr[]{A{"some"}, A{"string"}};
for (auto &a : arr) {
a.print_s();
}
}
With the move constructor commented out as shown, I get the error:
> g++ file.cc -g -std=c++11 -o file && ./file
file.cc: In function ‘int main()’:
file.cc:22:32: error: use of deleted function ‘A::A(const A&)’
22 | A arr[]{A{"some"}, A{"string"}};
| ^
file.cc:10:2: note: declared here
10 | A(const A &other) = delete;
| ^
file.cc:22:32: error: use of deleted function ‘A::A(const A&)’
22 | A arr[]{A{"some"}, A{"string"}};
| ^
file.cc:10:2: note: declared here
10 | A(const A &other) = delete;
| ^
If I uncomment the move constructor I get the output
constructor
constructor
some
string
So, the move constructor does not actually appear to be invoked.
Why is the move constructor needed? Have I made a mistake somewhere (e.g., a poorly implemented move constructor)?
With
A arr[]{A{"some"}, A{"string"}};
You are creating two temporary A objects and then copying/moving them into the array. Now, the compiler can optimize this copy/move away, but that class still needs to be copyable/moveable in order for this to happen. When you comment out your move constructor, the class is no longer copyable or moveble, so you get a compiler error.
It should be noted that this changed in C++17 with its guaranteed copy elision. The code will compile in C++17 and beyond for types that can't be copied or moved.
If you change
explicit A(std::string s) : s_(s) { puts("constructor"); }
to
A(std::string s) : s_(s) { puts("constructor"); }
then your main function could become
int main()
{
A arr[]{{"some"}, {"string"}};
for (auto &a : arr) {
a.print_s();
}
}
which will compile even if you can't copy or move an A.

A tricky question regarding Copy Constructor

My confusion lies at line Cube c = a;. I think it should call both default constructor and copy constructor, but in fact it only calls copy constructor.
Isn't Cube c, just like Cube a, a new object that should invoke default constructor?
class Cube
{
public:
int length_;
Cube(){
length_ = 1;
cout<< "Default Constr"<< endl;
}
Cube(const Cube & obj){
length_ = obj.length_;
cout<< "Copy Constr"<< endl;
}
};
Cube foo(){
Cube c;
return c;
}
int main() {
Cube a; //invoke default constructor only
Cube c = a; //invoke copy constructor only
return 0;
}
As others have pointed out, what you have here is copy initialization, so there's no way a default constructor would be used.
There is a slightly different case in which copy initialization can (at least theoretically) involve an extra step. Consider code like this:
class foo {
public:
foo(int) {}
};
int main() {
foo f = 1;
}
In this case, (at least before C++17) there were theoretically supposed to be two separate constructors involved. First, a temporary was constructed, initialized with 1, then the copy constructor was called to initialize f from that temporary object.
In this case, most compilers will generate code that just directly initializes f from q, so it's equivalent to foo f{1};. The compiler is still required to respect the fact that a copy is needed though, so if you delete the copy constructor, compilation will fail:
class foo {
foo(foo const &)= delete;
public:
foo(int) {}
};
int main() {
foo f = 1;
}
Result (with gcc):
trash9.cpp: In function 'int main()':
trash9.cpp:8:17: error: use of deleted function 'foo::foo(const foo&)'
foo f = 1;
^
trash9.cpp:2:9: note: declared here
foo(foo const &) = delete;
^~~
trash9.cpp:4:9: note: after user-defined conversion: 'foo::foo(int)'
foo(int) {}
^~~
But changes in the rules starting with C++17 mean that now even that is allowed (so if I add -std=c++17 to the compilation above, it succeeds).
When you write:
Cube c = a;
This is actually not an assignment but a copy-initialization.
In your case, it would be the same as if you had written:
Cube c(a);
Only the copy-constructor is called.
Keep in mind that an object is constructed only once, therefore only one constructor.
The default constructor is called.
It is used to initialize the object.
Then the copy constructor is used to set the state of the new object to be the same with the initial one.

Behaviour of copy constructor accepting const reference

In the following Code, in this line
A(A& b)
When using this compiler gives error as
c110.cpp:41: error: no matching function for call to ‘A::A(A)’
c110.cpp:8: note: candidates are: A::A(A&)
But as soon as i convert it into
A(const A& b)
Many many thanx in Advance
No error comes. Why is it so?
Code
class A
{
public:
static int cnt;
A(A& b)
{
cnt++;
cout<<"cnt="<<cnt<<endl;
}
A()
{
cnt++;
cout<<"cnt="<<cnt<<endl;
}
~A()
{
cnt--;
cout<<"cnt="<<cnt<<endl;
}
};
int A :: cnt=0;
A fun(A b)
{
return b;
}
int main()
{
A a;
A b=fun(a);
return 0;
}
Non-const references cannot bind to temporaries. If you pass a temporary as parameter, A& is illegal but const A& isn't.
The line
A b=fun(a);
does copy-initialization on the object returned by fun(a), which is a temporary.
Also, the copy constructor shouldn't take a non-const reference because, logically, you don't need to modify the object you're copying from.
I think its always safe to use A(const A&) type of syntax for copy construction rather than A(A&), because RVO may take place or not, its compiler dependent.
As in the above question RVO is not taking place and the temporary is been created, hence A(const A&) is safe to use.