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.
Given two types
B, such that an explicit conversion from
Bis valid, but an implicit conversion is not, why is
std::pair<A,A>implicitly convertible to
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
derivedto a function that takes a pointer to base.
The only operation in
std::pairthat 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?