<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/69334>69334</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[libc++] compile fails when using `std::unitialized_copy()` with an output iterator type that has `operator!=()` overload
</td>
</tr>
<tr>
<th>Labels</th>
<td>
libc++
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
tearfur
</td>
</tr>
</table>
<pre>
## Description
When using `std::uninitialized_copy()` from libc++:
```cpp
template< class InputIt, class NoThrowForwardIt >
NoThrowForwardIt uninitialized_copy( InputIt first, InputIt last,
NoThrowForwardIt d_first );
```
If the user overloaded `operator!=()` like this:
```cpp
template< class Iter >
bool operator!=( NoThrowForwardIt const& lhs, Iter const& rhs );
```
Compilation fails due to ambiguous overload resolution.
## Minimal reproducible example
<details>
<summary>main.cpp</summary>
```cpp
#include <array>
#include <iostream>
#include <iterator>
#include <memory>
namespace
{
template<typename T>
class myCrappyIterator
{
public:
using value_type = typename std::iterator_traits<T*>::value_type;
using difference_type = typename std::iterator_traits<T*>::difference_type;
using reference = typename std::iterator_traits<T*>::reference;
using pointer = typename std::iterator_traits<T*>::pointer;
using iterator_category = typename std::iterator_traits<T*>::iterator_category;
myCrappyIterator() = default;
explicit myCrappyIterator(T* const ptr)
: ptr_(ptr)
{
}
myCrappyIterator(myCrappyIterator const& that) = default;
myCrappyIterator(myCrappyIterator&& that) = default;
myCrappyIterator<T>& operator=(myCrappyIterator const& that) = default;
myCrappyIterator<T>& operator=(myCrappyIterator&& that) = default;
constexpr reference operator*() const noexcept
{
return *ptr_;
}
constexpr pointer operator->() const noexcept
{
return std::addressof(*ptr_);
}
constexpr myCrappyIterator& operator++() noexcept
{
++ptr_;
return *this;
}
constexpr myCrappyIterator operator++(int) const noexcept
{
myCrappyIterator old{ *this };
++(*this);
return old;
}
constexpr bool operator==(myCrappyIterator const& that) const noexcept
{
return this->ptr_ == that.ptr_;
}
constexpr bool operator!=(myCrappyIterator const& that) const noexcept
{
return !this->operator==(that);
}
private:
pointer ptr_;
template<typename Iter>
friend bool operator!=(myCrappyIterator const& lhs, Iter const& rhs) noexcept;
};
template<typename T, typename Iter>
constexpr bool operator!=(myCrappyIterator<T> const& lhs, Iter const& rhs) noexcept
{
return lhs.ptr_ == rhs;
}
} // namespace
int main()
{
static auto constexpr src = std::array{ 1, 2, 3, 4 };
auto dst = decltype(src){};
std::uninitialized_copy(std::begin(src), std::end(src), myCrappyIterator{ std::data(dst) });
return 0;
}
```
</details>
clang console output:
```console
In file included from main.cpp:1:
In file included from /usr/include/c++/v1/array:114:
In file included from /usr/include/c++/v1/algorithm:667:
In file included from /usr/include/c++/v1/functional:506:
In file included from /usr/include/c++/v1/__functional/function.h:24:
In file included from /usr/include/c++/v1/memory:819:
In file included from /usr/include/c++/v1/__memory/ranges_uninitialized_algorithms.h:22:
/usr/include/c++/v1/__memory/uninitialized_algorithms.h:45:41: error: use of overloaded operator '!=' is ambiguous (with operand types '(anonymous namespace)::myCrappyIterator<int>' and 'std::__unreachable_sentinel')
for (; __ifirst != __ilast && __idx != __olast; ++__ifirst, (void)++__idx)
~~~~~ ^ ~~~~~~~
/usr/include/c++/v1/__memory/uninitialized_algorithms.h:61:26: note: in instantiation of function template specialization 'std::__uninitialized_copy<int, const int *, const int *, (anonymous namespace)::myCrappyIterator<int>, std::__unreachable_sentinel>' requested here
auto __result = _VSTD::__uninitialized_copy<_ValueType>(_VSTD::move(__ifirst), _VSTD::move(__ilast),
^
main.cpp:82:10: note: in instantiation of function template specialization 'std::uninitialized_copy<const int *, (anonymous namespace)::myCrappyIterator<int>>' requested here
std::uninitialized_copy(std::begin(src), std::end(src), myCrappyIterator{ std::data(dst) });
^
/usr/include/c++/v1/__memory/uninitialized_algorithms.h:30:55: note: candidate function [with _Iter = (anonymous namespace)::myCrappyIterator<int>]
_LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR bool operator!=(const _Iter&, __unreachable_sentinel) _NOEXCEPT {
^
main.cpp:67:17: note: candidate function [with Iter = std::__unreachable_sentinel]
friend bool operator!=(myCrappyIterator const& lhs, Iter const& rhs) noexcept;
^
main.cpp:71:16: note: candidate function [with T = int, Iter = std::__unreachable_sentinel]
constexpr bool operator!=(myCrappyIterator<T> const& lhs, Iter const& rhs) noexcept
^
1 error generated.
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMWUtv4zgS_jXMhWjDIv08-OBHjDWw092YCWbnJtBSyeIuRWpJKp3soX_7gtTTluxxHhiMESi2yPrqXaySmDH8JAFWaLpB090DK2yq9MoC00mhH44qfl0hQhGheAcm0jy3XEk03qHxurz-KwWJC8PlCaPZ2NgY0TWi60JyyS1ngv8P4jBS-SsiC0SWaDbGiVYZFvwYIbJxf3TdBUSzcfkX5Xl5x0KWC2YB0S2OBDMGH2Re2INFpL7xVT2lWv3YK_2D6fhgMaKPJXFvZVCyGhEnXBuPW98QzP8uwfp84tBTYKca3Vxo0FXrkGCbAi4MaKyeQQvFYoidzVQOmlmlEQkQ3bVmEvw_gG3KzXsMZEG3NjgqJXCPTV-ZSEmn7AyL1HgbOJTmpk7Nn6u5VVnOBXNRghPGhcFxAdgqzLIjPxWqMI32WINRonBbR2f6lfH2C5c8YwJryLWKi4gfBWB4YVku4Gw73cZgHatGX0S3psgypl8RfcwYlyNnKrpFZN_ev21SRCiXkShiwIhumdasQ3O2xpWxGlh2bdlWZh9eziBTPXEky8DkLKr1nG96fravObht-KmhLT2fvW41y_PXQ833HCIvjoJHTURhjKvkfWaigNDBYkR3uMFvMrpWJLSacWsQ3T4hsnbc_XJL3wRICx7zJAENMvoIhwuQATYaqg3vY9CQD0Dnissyp94BXBEPwDaEEbNwUvr1fQx6MG2SNgx7geELjecXQ8IKYQeI4CUXPOJ2iNpJUFYHnFvtKkND5j6Irt39EJHF5XITjeWP3R2iXt5qy5JNmb2myJ1giMzeheS8QB8daVNcfWX9RGHvZXGHCi0XLw685LqTMe3xsK4io3StVPASQW4r6jPXuY8GW2iJEVl7Z9Pbnm051wlV8_3i1bzO-DJsOrybLGFxrMEYlXigUqDOgXVboAGLdoziG5VSvFuClRt7ljg3VHmm32uoXjD1hOLS3me2PpSI0XxTy-TluBS7o3opeNeg56o5tLvVOu9J6O7ezHlrcDiZXWw5n-CSj8canTvpDbLW_dPny4pIUIvbs0yFeVXiXPNn3xp0NKhz7EzVdnmonTj4c6rqKHCiOcj4zfpfax_PsqeRpxN0t9ocssXDUr7VT1VNfaO4521U7TGRmlE3shxVV7H6C0Zkj8geX3Z2_sqlxa5LrVr_C07GMssjzAqrOiFpdOSLfFv7fIs63-DA6ULchbrLpJfVHil2M4s_JCLhuymyMDpy7Oebvkcc2e3Rrlk9wslrUqGRbUsIMj5b6Dlmvmk3x8wyRBaxKc-z-e5s9GikqvwwHrD60HhSDgG9eaHun-XJm1gJwKqweWGvjl7lrmq0kzjhAnDV1sflgNvOHeuggRneisi-MBqRfXUbkX09G5P9c4DIvhpA1kEw-TiWOCnNbZohup7N5h_GSwoZuSGOCUTX0_Hsw4Bh2IFs8Ucpomvycf3rkWu9CJafIGsFR_aayROY8Dw9GmObUnzSRtRbsG-CTqbu4oIMg9auwK1xYQCrpPukoa6LGJF5XRvnmJvOZI7I4ge3ablVxr7emnL_gkklXzO3q61hZFnm6kCFdT2Ja-jm2AEhMm8SOwwLqYFFKTsKCA1IyyUIz6QzIiRe0AWiGxyGvH7G4qR2vwXzP33LG4Y8fmnXlH9gQzdV41ITu3qDyOJZ8dhXn2otfmm5_nQfjKaP5befPz_bTzPnIuLyA0vlj2rMJebSWCYtL5-ZqATX8d6cz9jkEHnMcs-lNXvluDQ_2VYNiDtffFs_cOP9nu0U9isuLf2v4b8FGAsxTkFD7WF_CIWhBlOI8iQKf__taXdTqfB3Jgp48rO_mxU6FJl6dkdY621_wAxuKB_oLdtnetc-aFodD51KvnD5G4w_1YWDun6eo2544e90pLfm_ryEo85R02nXWxGTMY-dRxofoenGV73wUD_gebetp7s6psJ_Hjbb79_Dfxx2j-H-12-_hOvNoe6n68Xtt6-_PT3-8f3XK51rGQReLl_stvha8Vzi8Ou3xz-2j9-futPoQAT7Az-Y32mTxiR_luut5vgvmRoGdZu7AhvM7tTtyStWVco3K_oXTh3X6lJQHvf4BNLxgHh00aU-xCsaL-mSPcAqmC3n02kwWQQP6Yod4RjEi-WSThNCY7YcH2d0BvFyMk8osOCBr8iY0GAczIPJeDIZj-aLgAbLZD6dTAglMEOTMWSMi5EQz9lI6dMDN6aA1WxJ6eRBsCMI418qEdJ500MImu4e9MoRfTkWJ4MmY8GNNS2M5Vb411EdsukOR_69AlTvFH5cfel05ZWTdziTVVffPHb1HY4f13HKzK2XMXUj9VBosUqtzf1bGT_UnbhNi-MoUhkie6dH9e9LrtW_IbKukjnbGET23jz_DwAA___e92N1">