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
(e.g., 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, e.g., 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!