I've browsed through a lot of questions related to conversion, but it seemed none of them discussing about explicit keyword in this way. Here's the code:
struct B;
struct A{
/*explicit*/ A(const B&){ cout << 1; } // *1
};
struct B{
/*explicit*/ operator A()const{ cout << 2; } // *2
};
void foo(const A &){}
int main(void){
B b;
foo( /*static_cast<A>*/ (b) ); // *3
}
Result: (Y: uncommented, N:commented, X: either)
# | *1 | *2 | *3 |output|
1 | N | N | N |error |
2 | N | N | Y | 1 |
3 | N | Y | N | 1 |
4 | N | Y | Y | 1 |
5 | Y | N | N | 2 |
6 | Y | N | Y | 1 |
7 | Y | Y | N |error |
8 | Y | Y | Y | 1 |
1, 7 are errors, which is normal.(ambiguous and no auto conversion)
2 seems that constructor have higher precedence, but why?
3, 5 are easy to understand.
4 is weird since it doesn't call the explicit one. why?
6 may be due to 'explicit' or constructor having higher precedence. Which one is the reason?
8 seems that constructor have higher precedence, but why?
Could someone offer some explanations? Thanks!
A very good question.
First of all, the explicit
thing doesn't mean "this has precedence if explicit conversion is required". It means "this thing can only be invoked explicitly". So it creates some situations where it cannot be invoked, not forces it to be invoked in other situations.
Another thing to consider is that static_cast
is direct initialization, while passing an argument to a function is copy initialization. Among other things, copy initialization never uses explicit constructors. Another thing to note is that direct initialization requires use of constructors for classes (explicit or not). Although that doesn't mean that a conversion can't perform direct initialization: it can be used to convert the argument of a constructor and if the constructor is a compiler-generated copy one, then it would look like the conversion function performed direct initialization (whereas in fact it was performed by the copy constructor). Try declaring a copy constructor without defining it (the disable-copy technique) and you'll see that conversion function no longer works in the direct initialization context: it'll compile, but will cause a linking error.
With that in mind:
explicit
only prevents it from being invoked implicitly, it doesn't force its use in explicit contexts.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