Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why std::pair calls explicit constructors in assignment

Consider the following code:

#include<iostream>
#include<utility>


struct Base
{
    int baseint;
};

struct Der1 : Base
{
    int der1int;
    Der1() : der1int(1) {}
    explicit Der1(const Base& a) : Base(a), der1int(1)
    {
        std::cerr << "cc1" << std::endl;
    }
};

struct Der2 : Base
{
    int der2int;
    Der2() : der2int(2) {}
    explicit Der2(const Base& a) : Base(a), der2int(2)
    {
        std::cerr << "cc2" << std::endl;
    }
};


template <typename T, typename U>
struct MyPair
{
    T first;
    U second;
};

int main()
{
    Der1 d1;
    Der2 d2;

    std::pair<Der1, int> p1;
    std::pair<Der2, int> p2;

    p1 = p2; // This compiles successfully

    MyPair<Der1, int> mp1;
    MyPair<Der2, int> mp2;

    mp1 = mp2; // This will raise compiler error, as expected.
}

Tested under GCC 4.5.2

The reason lies in std::pair sources:

  /** There is also a templated copy ctor for the @c pair class itself.  */
  template<class _U1, class _U2>
    pair(const pair<_U1, _U2>& __p)
    : first(__p.first),
      second(__p.second) { }

Is that behaviour compliant with the C++ standard? For a first sight it looks inconsistent and counterintuitive. Do the other implementations of STL work the same way?

like image 747
Rafał Rawicki Avatar asked Feb 23 '23 13:02

Rafał Rawicki


1 Answers

I am not sure that I understand the question, but basically you are asking why two unrelated std::pair can be implicitly convertible even if the instantiating types are not implicitly convertible. That is, why the implicitly convertible property of the instantiating types does not propagate to the pair.

The standard does not provide explicit assignment operators for the std::pair template, which means that it will use the implicitly generated assignment operator. To be able to assign pairs of convertible types, it relies on a templated constructor that allows an implicit conversion from std::pair<A,B> to std::pair<C,D>, the behavior of which is defined in §20.2.2 [lib.pairs]/4

template<class U, class V> pair(const pair<U, V> &p);

Effects: Initializes members from the corresponding members of the argument, performing implicit con- versions as needed.

The standard seems to only require the implementation to use implicit conversions, and in this particular implementation the conversion is actually explicit, which seems to contradict the wording of the standard.

like image 97
David Rodríguez - dribeas Avatar answered Mar 06 '23 04:03

David Rodríguez - dribeas