Here is my code:
1 #include <cstdio>
2
3 struct Foo;
4
5 struct Bar {
6 Foo *foo;
7 Bar(const Foo& fo) {
8 printf("In Bar copy_contr\n");
9 }
10
11 Bar& operator=(Foo& fo) {
12 printf("In Bar assignment\n");
13 this->foo = &fo;
14 }
15 };
16
17 struct Foo {
18 Bar *bar;
19 Foo() {
20 printf("In default\n");
21 }
22
23 Foo(const Bar& b) {
24 printf("In Foo copy constructor\n");
25 }
26
27 operator Bar() {
28 printf("In typecast from Foo to Bar\n");
29 return *(this->bar);
30 }
31
32 };
33
34
35 int f(Bar b) {
36 return 0;
37 }
38
39 int main() {
40 Foo fo;
41 f(fo);
42 Bar *b = &static_cast<Bar>(fo);
43
44 return 0;
45 }
Here is the print out:
In default
In typecast from Foo to Bar
In Bar copy_contr
I am confused at the 3rd printout: how come copy constructor is called, it should be type casting, there is specific static_cast there.
I also have an interesting find – if I comment out line27 – line30, basically make disappear the typecasting function, the printout changes to
In default
In Bar copy_contr
In Bar copy_contr
So it seems the compiler has some mechanism to search some conversion function in some order, anyone has standard hardy to tell what is the mechanism?
I am using g++ v4.1.2.
Thanks!
The result of the expression static_cast<T>(v) is the result of converting the expression v to type T.
An expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t.
The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion.
It should be clear from this why the converting constructor is called then in this case.
You are asking why the conversion function Foo::operator Bar is selected (if available) to convert the parameter fo from Foo to Bar instead of the converting constructor Bar::Bar(const Foo&)….
User-defined conversions are applied only where they are unambiguous. However note the following in your paticular case:
Therefore the conversion chosen is Foo::operator Bar() for the same reason that:
the non-const version of f is selected above. That Foo fo is non-const, so the non-const version is selected.
If the conversion function was const OR the converting constructor took a non-const reference, than there would be an ambiguity and it would not compile.
If the conversion function was const AND the converting constructor took a non-const reference, it would select the converting constructor instead of the conversion function.