简体   繁体   中英

Why does `std::pair<int, movable>` require a [deleted] `const&` copy constructor?

I'm busy testing an implementation of various generic algorithms and I'm using types with minimal support of provided functions. I came across this weird setup when using a std::pair<T, movable> with some type T (eg, int ) and a movable type defined like this:

struct movable
{
    movable() {}
    movable(movable&&) = default;
    // movable(movable const&) = delete;
    movable(movable&) = delete;
};

The idea is have a type which is movable but not copyable. That works great, eg, with expressions like this:

movable m1 = movable();
movable m2 = std::move(m1);

However, when trying to use this type as a member of std::pair<...> it fails! To make get the code to compile it is necessary to add the delete d(!) copy constructor taking a movable const& (or have only that version). The copy constructor taking a non- const reference is insufficient:

#include <utility>
auto f() -> std::pair<int, movable> {
    return std::pair<int, movable>(int(), movable());
}

What is going on here? Is std::pair<...> overspecified by mandating that std::pair(std::pair const&) is = default ed?

The problem seems to be down to the specification of std::pair 's copy constructor (in 20.3.2 [pairs.pair] synopsis):

  namespace std { template <class T1, class T2> struct pair { ... pair(const pair&) = default; ... }; } 

A quick check with my implementation implies that the obvious implementation copying the two members does not require the const& version of the movable copy constructor. That is, the offensive part is the = default on pair 's copy constructor!

std::pair copy constructor is declared as follows:

pair(const pair&) = default;

By declaring this copy constructor for movable :

movable(movable&) = delete;

you inhibit implicit creation of movable(const movable&) (so it's not even deleted, there's just no such constructor), thus this is the only copy constructor you have. But std::pair copy constructor requires a copy constructor of its members to take const reference, so you get compile error.

If you add this:

movable(movable const&) = delete;

or (better) just remove movable(movable&) = delete; declaration, you now have the movable(movable const&) constructor, and because it's deleted, the std::pair copy constructor also becomes deleted.

Update : Let's consider a simpler example demonstrating the same issue. This doesn't compile:

template <typename T>
struct holder {
    T t;
    // will compile if you comment the next line
    holder(holder const&) = default;
    // adding or removing move constructor changes nothing WRT compile errors
    // holder(holder&&) = default;
};

struct movable {
    movable() {}
    movable(movable&&) = default;
    // will also compile if you uncomment the next line
    //movable(movable const&) = delete;
    movable(movable&) = delete;
};

holder<movable> h{movable()};

It will compile if you comment the copy constructor of holder , because this is how implicit copy constructor generation works ( [class.copy]/8 :

The implicitly-declared copy constructor for a class X will have the form

X::X(const X&)

if each potentially constructed subobject of a class type M (or array thereof) has a copy constructor whose first parameter is of type const M& or const volatile M& . Otherwise, the implicitly-declared copy constructor will have the form

X::X(X&)

That is, when you comment out the declaration holder(holder const&) = default; the implicitly declared copy constructor of holder will have the form holder(holder&) . But if you don't, T 's copy constructor has take const T& (or const volatile T& ) because this is what will be called in memberwise copy procedure described in [class.copy]/15 .

And if holder has a move constructor, it's even easier - if you comment out holder(holder const&) = default; , the implicitly declared copy constructor of holder will be just deleted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM