The problem Rafał has is with implicit conversions. In his application he has two types that are convertible, but only explicitly convertible. He is surprised that an
std::pair<>
that contains one of those types is implicitly convertible to a std::pair<>
of that contains the second type.The problem
Given two types
A
and B
, such that an explicit conversion from A
to B
is valid, but an implicit conversion is not, why is std::pair<A,A>
implicitly convertible to std::pair<B,B>
? Well, the answer to this type of question is usually simple: the properties of the types used to instantiate a template do not propagate to the template itself. That is the reason why you cannot pass a
std::vector< derived* >
to a function that requires a std::vector< base* >
, even if you can pass a pointer to derived
to a function that takes a pointer to base.The only operation in
std::pair
that allows for conversions is a constructor template. The implementation of that template in the STL shipped with gcc uses the initialization-list to initialize the members of the pair
. Because that is explicit initialization, the compiler gladly accepts the code.But, is this the case?
No, not really. In this case the standard is by Rafał's side. The description of the behavior for that particular conversion constructor is stated in §20.2.2:
template <typename U, typename V>
pair( const pair<U,V> & p );
Initializes members from the corresponding members of the argument, performing implicit conversions as needed.
The standard seems quite clear in stating that implicit conversions are to be used, so this seems like a bug in the compiler side not adhering to the standard. As always, the interesting question is the why.
Can we implement that constructor template with the semantics defined in the standard?
We cannot use implicit conversions in the constructor without adding additional requirements to the instantiating types (for example, using default construction and assignment of the arguments). But if our goal is just to abide the standard and reject all calls to that template when an implicit conversion is not available, that is easy.
Detecting implicit convertibility is simple, and we can add a static assert to the constructor. The con of the approach is that while this will inhibit implicit conversions when the
pair
's elements are not implicitly convertible, it does not allow for explicit conversions of the pairs. But that is probably fine. Or can we do better?
third paragraph should read "why is std::pair < A, A > implicitly convertible to std::pair < B, B > ?" - nice post though! (I messed up with the brackets)
ReplyDeleteThanks for the heads up with respect to the typo. I am actually surprised that *anyone* has read this... I thought I had at least a few weeks where I could play with the tool and learn how to write, post, format code...
ReplyDeleteDavid Could you please find some time and continue your blogs? its really helpful to learn from you. Maybe when you answer a question at stack overflow you can extend those answers here(if possible) or pick out a new topic.This is a request since i can understand clearly when you explain. cheers:-).
ReplyDeleteMerit Casino | Online Casino Review India
ReplyDeleteThis casino offers online casino games and the best betting products in the world. All of the major 메리트카지노 online casinos provide generous bonuses for new