I cannot undestand why a copy constructor is called instead of a compile error.
I have declare two classes A B , which are independent . A is not based/derived of B. The only connection between them is that in B I use an operator that converts B to A
I have defined an operator = that gets as an argument a const reference of B.
In main I have written the following instnace of B = instance of A. I expect that a compile error will be generated. But the operator = is called
class A {};
class B {
public:
// conversion from A (constructor):
B()
{
cout << "1." << endl;
}
B(const A& x)
{
cout << "4." << endl;
}
// conversion from A (assignment):
B& operator= (const B& x)
{
cout << "3." << endl;
return *this;
}
// conversion to A (type-cast operator)
operator A() {
cout << "2." << endl;
return A();
}
};
int main()
{
A foo;
B bar; // calls constructor
bar = foo; // calls assignment
//foo = bar; // calls type-cast operator
char c;
c = getchar();
return 0;
}
I expect compile error. But the following sequence is printed
1 4 3 .
I hardly undestand how the copy constructor is called and why the operator = does not generate problem
Thank you
You have an implicit constructor
B::B(const A&)
which performs the conversion that you don't want. You can change the signature to
explicit B(const A&);
to trigger a compilation error. Note that it's good practice to mark constructors with one argument explicit by default (there is a clang-tidy check for it, too), just to avoid such conversions by accident (IMHO, it would even be better if constructors that can be constructed with a single argument would be explicit by default with the ability to make the implicit).
It's not a copy constructor that you have, it's a conversion constructor. The conversion constructor is called because you can turn a A into a B.
Do this:
explicit B(const A& x)
And now you will forbid the implicit conversion from A to B.
When you do:
bar = foo;
The compiler looks for sensible operations and allows for one conversion at most. It can use the copy assignment from B, and it knows it can create a B out of an A (because the constructor is not explicit), so it does this silently.
As #lubgr said, clang-tidy has a rule to check these and this is part of the C++ core guidelines.
I expect the following compile error will be generated
no match for 'operator=' ... note: no known conversion for argument 1 from 'A' to 'const B&'
There is no reason to expect such error, because there is a known conversion from A to const B&. B has a converting constructor for A:
B(const A& x)
The only connection between them is that in B I use an operator that converts B to A
... and the second connection between them is that in B, you use a constructor that converts A to B.
You are right that this a conversion cunstroctor. But why this called when the assignement bar = foo takes place.
Because the given operand of the assignment has the type A, while the declared argument type is const B&.
In cases where the argument type does not match the declaration, the compiler checks whether there exists an implicit conversion sequence which could be used to convert the argument. As, A is implicitly convertible to B, such implicit conversion sequence exists and will be used.
Related
This question already has answers here:
C++ template copy constructor on template class
(3 answers)
Closed 2 years ago.
Why is it that the following code fails to compile (complains about deleted copy constructor):
struct C {
int i;
C(const C&) = delete;
C(int i) : i(i) {}
template <typename T>
C(const T& value) {
cout << "in templatized constructor!\n";
this->i = value.i * 2;
}
};
int main()
{
C s1{4};
C s2{s1};
cout << s2.i;
}
But when i remove the const from the templatized copy constructor, everything works:
template <typename T>
C(T& value) {
cout << "in templatized constructor!\n";
this->i = value.i * 2;
}
Two questions:
(1) Why isn't the template contructor used as a fall-back when the generated copy constructor is deleted?
(2) Even though "templates can't be copy constructors" - how/why is it that the C(T&); constructor IS being used as a copy constructor (in the second example) ? surely this contradicts the idea that templates can't be copy constructors?
It's just overload resolution. In C s2{s1};, you are looking for a constructor of C that can take a (non-const) C lvalue argument. For template<typename T> C(T const&), the "closest" this constructor can get to matching the argument list is setting T = C, so you get C(C const&) (this solution for T is found by template argument deduction, which we don't need to go into). The copy constructor C(C const&) = delete; can also be called with this argument list. The two implicit conversion sequences involved (C lvalue undergoes identity conversion to bind to C const&), are also exactly the same, so neither overload is immediately "better" than the other than the other. However, the deleted one is not a template, so it's considered to be better anyway. The deleted overload is chosen, causing an error. If you have instead template<typename T> C(T&), then it can get closer to the given argument list, by setting T = C to get C(C&). Now, the implicit conversion sequence where a C lvalue binds to a C& (the case of the template) is better than the implicit conversion sequence where a C lvalue binds to a C const& (the copy constructor), since there are fewer qualifiers to add, so now the template wins and the code compiles.
Addressing the comments, your templated constructor indeed isn't a copy constructor. According to cppreference,
A copy constructor of class T is a non-template constructor...
Also, you may be misunderstanding what = delete; means. C(C const&) = delete; does not mean "there is not an overload with this signature", it means "there is an overload with this signature, and trying to call it is an error". You can't not have a copy constructor as one of the overloads of a class's constructor. deleteing it only makes it an error to use that overload but doesn't stop overload resolution from picking it over another overload.
Consider the following two classes :
#define PRETTY(x) (std::cout << __PRETTY_FUNCTION__ << " : " << (x) << '\n')
struct D;
struct C {
C() { PRETTY(this);}
C(const C&) { PRETTY(this);}
C(const D&) { PRETTY(this);}
};
struct D {
D() { PRETTY(this);}
operator C() { PRETTY(this); return C();}
};
We are interested in the overload resolution between the two constructors :
C::C(const C&);
C::C(const D&);
This code work as expected :
void f(const C& c){ PRETTY(&c);}
void f(const D& d){ PRETTY(&d);}
/*--------*/
D d;
f(d); //calls void f(const D& d)
since void f(const D& d) is a better match.
But :
D d;
C c(d);
(as you can see here)
calls D::operator C() when compiling with std=c++17, and calls C::C(const D&) with std=c++14 on both clang and gcc HEAD.
Moreover this behaviour has changed recently :
with clang 5, C::C(const D&) is called with both std=c++17 and std=c++14.
What is the correct behaviour here ?
Tentative reading of the standard (latest draft N4687) :
C c(d) is a direct-initialization which is not a copy elision ([dcl.init]/17.6.1). [dcl.init]/17.6.2 tells us that applicable constructors are enumerated and that the best one is chosen by overload resolution. [over.match.ctor] tells us that the applicable constructors are in this case all the constructors.
In this case : C(), C(const C&) and C(const D&) (no move ctor). C() is clearly not viable and thus is discarded from the overload set. ([over.match.viable])
Constructors have no implicit object parameter and so C(const C&) and C(const D&) both take exactly one parameter. ([over.match.funcs]/2)
We now go to [over.match.best]. Here we find that we need to determine which
of these two implicit conversion sequences (ICS) is better. The ICS of
C(const D&) only involves a standard conversion sequence, but the ICS of C(const C&) involves a user-defined conversion sequence.
Therefore C(const D&) should be selected instead of C(const C&).
Interestingly, these two modifications both causes the "right" constructor to
be called :
operator C() { /* */ } into operator C() const { /* */ }
or
C(const D&) { /* */ } into C(D&) { /* */ }
This is what would happen (I think) in the copy-initialization case where
user-defined conversions and converting constructors are subject to overload
resolution.
As Columbo recommends I filed a bug report with gcc and clang
gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82840
clang bug https://bugs.llvm.org/show_bug.cgi?id=35207
Core issue 243 (17 years old!):
There is a moderately serious problem with the definition of overload
resolution. Consider this example:
struct B;
struct A {
A(B);
};
struct B {
operator A();
} b;
int main() {
(void)A(b);
}
This is pretty much the definition of "ambiguous," right? You want to convert a B to an A, and there are two equally good ways of
doing that: a constructor of A that takes a B, and a conversion
function of B that returns an A.
What we discover when we trace this through the standard,
unfortunately, is that the constructor is favored over the conversion
function. The definition of direct-initialization (the parenthesized
form) of a class considers only constructors of that class. In this
case, the constructors are the A(B) constructor and the
(implicitly-generated) A(const A&) copy constructor. Here's how they
are ranked on the argument match:
A(B): exact match (need a B, have a B)
A(const A&): user-defined conversion (B::operator A used to convert B to A)
In other words, the
conversion function does get considered, but it's operating with, in
effect, a handicap of one user defined conversion. To put that a
different way, this problem is a problem of weighting, not a problem
that certain conversion paths are not considered. […]
Notes from 10/01 meeting:
It turns out that there is existing practice both ways on this issue,
so it's not clear that it is "broken". There is some reason to feel
that something that looks like a "constructor call" should call a
constructor if possible, rather than a conversion function. The CWG
decided to leave it alone.
Seems like you're right. Moreover, Clang and GCC selecting the conversion operator is hardly the best choice, neither according to wording nor intuition, so unless this is due to backward compatibility (and even then), a bug report would be appropriate.
How it comes that operation like foo = int can be done by both foo(int) (conversion constructor) and foo::operator=(int) (overloaded assignment operator)? When one be called instead of other (maybe one is rudimentary)?
#include <iostream>
class foo
{
public:
foo(){}
foo(int r_value)
{
std::cout << "\nfoo::foo(int)\n";
}
void operator=(int r_value)
{
std::cout << "\nfoo::operator=(int)\n";
}
};
int main()
{
foo f;
f = 57;
return 0;
}
Code above makes operator=(int) to run when both exist and foo(int) if operator=(int) is commented (or opposite).
This is basic overload resolution. Both overloads are viable:
Binding 57 to foo::operator=(int) (exact match)
Implicitly converting 57 to foo via the converting constructor, and binding the temporary foo object to the implicitly defined foo::operator=(foo const &).
Since the latter requires more conversions than the former, it is a less-good match, and the former overload is chosen.
You can still achieve the second call by making it explicit:
f = foo(57); // binds perfectly to foo::operator=(foo const &)
The full set of rules for overload resolution are rather long and involved, but in individual cases like this the answer is straight-forward. See 13.3 ([over.match]) for the full, gory details, though.
There is a difference:
foo a = 10;
Calls foo::foo(int)
foo a;
a = 10;
Calls foo::operator=(int) in a
Both of the implementations are different. The first is a Constructor and the second is an assignment. The Use cases varies, and each of them would be called accordingly based on the use case.
Use Case
The Constructor is called foo::foo(int)
foo f = 57;
The Assignment is called foo::operator=(int)
foo f;
f = 57;
Note
Using assignment in the above use case and in your example has more overhead, as it called the default constructor along with the assignment.
For this statement
f = 57;
the compiler at first considers all functions operator =. There are two such functions: the explicitly defined by you and the copy assignment operator implicitly defined by the compiler. The first one is the best suitable function. So it is called.
If you will comment this assignment operator then the compiler has only one function operator =. It is the implicitly defined copy assignment operator. But it can not be applied directly. So the compiler seeks a way to convert supplied argument to type foo. And it can do this by calling the conversion construuctor.
struct A {};
struct B
{
B (A* pA) {}
B& operator = (A* pA) { return *this; }
};
template<typename T>
struct Wrap
{
T *x;
operator T* () { return x; }
};
int main ()
{
Wrap<A> a;
B oB = a; // error: conversion from ‘Wrap<A>’ to non-scalar type ‘B’ requested
oB = a; // ok
}
When oB is constructed then Why B::B(A*) is NOT invoked for Wrap<T>::operator T () ? [Note: B::operator = (A*) is invoked for Wrap<T>::operator T () in the next statement]
The problem is that the number of user-defined conversions that are invoked implicitly is limited (to 1) by the Standard.
B ob = a;
implies two user conversions:
on a: Wrap<A>::operator A*() should be called
on the result: B::B(A*) should be called
#James Kanze's explanation: this syntax is called "copy initialization", effectively equivalent to B ob = B(a) (with the copy being elided most of the time). This is different from B ob(a) which is a "direct initialization" and would have worked.
if you explicitly qualify any of this, it will work, for example:
B ob = B(a);
On the other hand, for the second case there is no issue:
ob = a;
is short-hand for:
ob.operator=(a);
And thus only one user-defined conversion is required, which is allowed.
EDIT:
Since it's been required in a comment (to Kirill's answer) we can take a guess at the motive.
Chained conversions could be long, very long, and therefore:
could surprise users -- implicit conversions may already be surprising as it is...
could lead to an exponential search of the possibilities (for the compiler) -- it would need to go from both ends, trying to check all possible conversions, and somehow "join" the two (with the shortest path possible).
Furthermore, as long as there is more than 1 conversion, you run into the risk of having cycles, which would have to be detected (even though diagnostic would probably not be required, and be subject to Quality Of Implementation).
So, since a limit is necessary to avoid infinitely long searches (it could have been left unspecified, with a minimum required), and since beyond 1 we may have new issues (cycles), then 1 seems as good a limit as any after all.
It's because you're using "copy initialization". If you write the
declaration of oB:
B oB(a);
, it should work. The semantics of the two initializations are
different. For B oB(a), the compiler tries to find a constructor
which can be called with the given arguments. In this case, B::B(A*)
can be called, because there is an implicite conversion from Wrap<A>
to A*. For B oB = a, the semantics are to implicitly convert a to
type B, then use the copy constructor of B to initialize oB. (The
actual copy can be optimized out, but the legality of the program is
determined as if it weren't.) And there is no implicit conversion of
Wrap<A> to B, only of Wrap<A> to A*.
The assignment works, of course, because the assignment operator also
takes a A*, and so the implicit conversion comes into play.
The Standard doesn't allow chained implicit conversion. If it was allowed, then you could have written such code:
struct A
{
A(int i) //enable implicit conversion from int to A
};
struct B
{
B(const A & a); //enable implicit conversion from A to B
};
struct C
{
C(const B & b); //enable implicit conversion from B to C
};
C c = 10; //error
You cannot expect that 10 will convert to A which then will convert to B which then converts to C.
B b = 10; //error for same reason!
A a = 10; //okay, no chained implicit conversion!
B ba = A(10); //okay, no chained implicit conversion!
C cb = B(A(10)); //okay, no chained implicit conversion!
C ca = A(10); //error, requires chained implicit conversion
The same rule applies for implicit conversion that invokes operator T() implicitly.
Consider this,
struct B {};
struct A
{
A(int i); //enable implicit conversion from int to A
operator B(); //enable implicit conversion from B to A
};
struct C
{
C(const B & b); //enable implicit conversion from B to C
};
C c = 10; //error
You cannot expect that 10 will convert to A which then will convert to B(using operator B()) which then converts to C. S
Such chained implicit conversions are not allowed. You've to do this:
C cb = B(A(10); //okay. no chained implicit conversion!
C ca = A(10); //error, requires chained implicit conversion
This is because C++ Standard allows only one user-defined conversion. According to §12.3/4:
At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single
value.
B oB = a; // not tried: ob( a.operator T*() ), 1 conversion func+1 constructor
oB = a; // OK: oB.operator=( a.operator T*() ), 1 conversion func+1 operator=
As a workaround you can use explicit form of calling the constructor:
B oB( a ); // this requires only one implicit user-defined conversion
This example is from "Thinking in C++", I have one question regarding compiler synthesizing the operator conversion function.
Question
When object of class Four is passed (in the function call f()), the overload operation () is called. But I am not able to make out the logic used (compiler synthesizes the operation call) by compiler to achieve this conversion.
At max, I can expect explicit conversion behavior, like
1. obj3 = (Three)obj4;
2. obj3 = Three(obj4);
3. obj3 = static_cast<Three> (obj4);
Now for any one of the above conversion - how does the compiler synthesize,
(Three) obj4.operator()?
May be I am missing some major point.
Example
//: C12:Opconv.cpp
// Op overloading conversion
class Three {
int i;
public:
Three(int ii = 0, int = 0) : i(ii) {}
};
class Four {
int x;
public:
Four(int xx) : x(xx) {}
operator Three() const { return Three(x); }
};
void g(Three) {}
int main() {
Four four(1);
g(four);
g(1); // Calls Three(1,0)
} ///:~
First of all it is not operator() which you have provided, it is operator Three. This operator tells the compiler how to convert an object of class Four to an object of class Three. In g(four) call compiler is using this operator since the function g is expecting an argument of type Three. Since there is an conversion available compiler is using it. In the second case, since the constructor of Three is not declared as explicit and it is possible to construct a object of class Three using a single integer (using Three constructor) compiler is using that constuctor to create an object of the class Three so that function g can be called.
First of all, class Four does not contain an operator(), but it does have an operator Three(), which is a conversion operator.
In the line
g(four);
the compiler needs to convert four to an object of class Three and synthesises a call to operator Three() to perform that conversion.
The synthesised conversion is equivalent to
g(four.operator Three());