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]
A constructor for a class type is called whenever a new instance of that type is created. If a cast creates a new object of that class type then a constructor is called.
When you use static_cast , by defaut (i.e. without optimizations activated) it calls the conversion constructor of the object you are trying to cast into (if it exists). For instance, in this code. The highlighted expression would call the following constructor (if existent): Foo(const Bar &) .
Cast operator: () A type cast provides a method for explicit conversion of the type of an object in a specific situation.
A Cast operator is an unary operator which forces one data type to be converted into another data type. Static Cast: This is the simplest type of cast which can be used.
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:
a
: Wrap<A>::operator A*()
should be calledB::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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With