Since GCC 6 in C++ the declaration/definition of a unique_ptr<T[]>::reset method (not the one, that accepts only nullptr_t) looks like this:
template <typename _Up,
typename = _Require<
__or_<is_same<_Up, pointer>,
__and_<is_same<pointer, element_type*>,
is_pointer<_Up>,
is_convertible<
typename remove_pointer<_Up>::type(*)[],
element_type(*)[]
>
>
>
>>
void
reset(_Up __p) noexcept
{
using std::swap;
swap(std::get<0>(_M_t), __p);
if (__p != nullptr)
get_deleter()(__p);
}
This was changed at some point to implement N4089. According to that document:
This function behaves the same as the reset member of the primary template, except that it shall not participate in overload resolution unless either
—
Uis the same type aspointer, or—
pointeris the same type aselement_type*,Uis a pointer typeV*, andV(*)[]is convertible toelement_type(*)[].
Let's consider the following example:
std::unique_ptr<const char []> ptr1;
std::unique_ptr<char []> ptr2(new char[5]);
ptr1 = std::move(ptr2);
Since version 6 GCC produces an error, complaining that it cannot call std::swap with const char*& and char*&.
reset method takes place in the overload resolution as char[] is convertible to const char[], but naturally std::swap awaits two references of the same type.
Is this considered to be a correct behavior? If so, then why? If I can implicitly convert char[] to const char[], why the same should not be possible with unique_ptr?