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