I am trying to play around with copy and swap idiom to understand it better, so I have defined the following class:
#include <iostream>
#include <algorithm>
#include <utility>
class dumb_array
{
public:
dumb_array(std::size_t size = 0)
: mSize(size)
, mArray(size ? new int[size] : nullptr)
{}
dumb_array(const dumb_array& rhs)
: mSize(rhs.mSize)
, mArray(mSize ? new int[mSize]() : nullptr)
{
std::copy(rhs.mArray, rhs.mArray + mSize, mArray);
}
friend void swap(dumb_array& lhs, dumb_array& rhs) noexcept
{
std::swap(lhs.mSize, rhs.mSize);
std::swap(lhs.mArray, rhs.mArray);
}
dumb_array& operator=(dumb_array rhs)
{
std::swap(*this, rhs);
return *this;
}
dumb_array(dumb_array&& rhs) noexcept
: dumb_array()
{
swap(*this, rhs);
}
dumb_array& operator=(dumb_array&& rhs) noexcept
{
if (this != &rhs)
swap(*this, rhs);
return *this;
}
int& operator[](const std::size_t& idx)
{
return mArray[idx];
}
~dumb_array()
{
delete[] mArray;
}
private:
std::size_t mSize{0};
int* mArray{nullptr};
};
int main()
{
dumb_array a1{3};
a1[0] = 2; a1[1] = 3; a1[2] = 4;
std::cout << a1[0] << "\t" << a1[1] << "\t" << a1[2] << std::endl;
dumb_array a2{a1};
std::cout << a2[0] << "\t" << a2[1] << "\t" << a2[2] << std::endl;
dumb_array a3;
a3 = a2;
std::cout << a3[0] << "\t" << a3[1] << "\t" << a3[2] << std::endl;
return 0;
}
As you can notice, instead of friend swap
function I have used std::swap
inside copy assignment operator, because I already have both move constructor and move assignment operators defined which means that std::swap
should be able to move dump_array
object.
The thing is that I am getting compile error when using std::swap
function:
<source>: In member function 'dumb_array& dumb_array::operator=(dumb_array)':
<source>:28:18: error: no matching function for call to 'swap(dumb_array&, dumb_array&)'
28 | std::swap(*this, rhs);
| ~~~~~~~~~^~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/exception:164,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/ios:41,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/ostream:40,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/iostream:41,
from <source>:1:
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/exception_ptr.h:230:5: note: candidate: 'void std::__exception_ptr::swap(exception_ptr&, exception_ptr&)'
230 | swap(exception_ptr& __lhs, exception_ptr& __rhs)
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/exception_ptr.h:230:25: note: no known conversion for argument 1 from 'dumb_array' to 'std::__exception_ptr::exception_ptr&'
230 | swap(exception_ptr& __lhs, exception_ptr& __rhs)
| ~~~~~~~~~~~~~~~^~~~~
In file included from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/exception_ptr.h:41:
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/move.h:189:5: note: candidate: 'template<class _Tp> constexpr std::_Require<std::__not_<std::__is_tuple_like<_Tp> >, std::is_move_constructible<_Tp>, std::is_move_assignable<_Tp> > std::swap(_Tp&, _Tp&)'
189 | swap(_Tp& __a, _Tp& __b)
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/move.h:189:5: note: template argument deduction/substitution failed:
In file included from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/move.h:37:
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using std::__enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = void]':
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/type_traits:2224:11: required by substitution of 'template<class ... _Cond> using std::_Require = std::__enable_if_t<std::__and_<_Bn>::value> [with _Cond = {std::__not_<std::__is_tuple_like<dumb_array> >, std::is_move_constructible<dumb_array>, std::is_move_assignable<dumb_array>}]'
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/move.h:189:5: required by substitution of 'template<class _Tp> constexpr std::_Require<std::__not_<std::__is_tuple_like<_Tp> >, std::is_move_constructible<_Tp>, std::is_move_assignable<_Tp> > std::swap(_Tp&, _Tp&) [with _Tp = dumb_array]'
<source>:28:18: required from here
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/type_traits:116:11: error: no type named 'type' in 'struct std::enable_if<false, void>'
116 | using __enable_if_t = typename enable_if<_Cond, _Tp>::type;
| ^~~~~~~~~~~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/move.h:213:5: note: candidate: 'template<class _Tp, long unsigned int _Nm> constexpr std::__enable_if_t<std::__is_swappable<_Tp>::value> std::swap(_Tp (&)[_Nm], _Tp (&)[_Nm])'
213 | swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/move.h:213:5: note: template argument deduction/substitution failed:
<source>:28:18: note: mismatched types '_Tp [_Nm]' and 'dumb_array'
28 | std::swap(*this, rhs);
| ~~~~~~~~~^~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/stl_algobase.h:64,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/string:51,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/locale_classes.h:40,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/ios_base.h:41,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/ios:44:
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/stl_pair.h:879:5: note: candidate: 'template<class _T1, class _T2> constexpr typename std::enable_if<std::__and_<std::__is_swappable<_T1>, std::__is_swappable<_T2> >::value>::type std::swap(pair<_T1, _T2>&, pair<_T1, _T2>&)'
879 | swap(pair<_T1, _T2>& __x, pair<_T1, _T2>& __y)
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/stl_pair.h:879:5: note: template argument deduction/substitution failed:
<source>:28:18: note: 'dumb_array' is not derived from 'std::pair<_T1, _T2>'
28 | std::swap(*this, rhs);
| ~~~~~~~~~^~~~~~~~~~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/stl_pair.h:896:5: note: candidate: 'template<class _T1, class _T2> typename std::enable_if<(! std::__and_<std::__is_swappable<_T1>, std::__is_swappable<_T2> >::value)>::type std::swap(pair<_T1, _T2>&, pair<_T1, _T2>&)' (deleted)
896 | swap(pair<_T1, _T2>&, pair<_T1, _T2>&) = delete;
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/stl_pair.h:896:5: note: template argument deduction/substitution failed:
<source>:28:18: note: 'dumb_array' is not derived from 'std::pair<_T1, _T2>'
28 | std::swap(*this, rhs);
| ~~~~~~~~~^~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/string:54:
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/basic_string.h:3988:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> constexpr void std::swap(__cxx11::basic_string<_CharT, _Traits, _Allocator>&, __cxx11::basic_string<_CharT, _Traits, _Allocator>&)'
3988 | swap(basic_string<_CharT, _Traits, _Alloc>& __lhs,
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/basic_string.h:3988:5: note: template argument deduction/substitution failed:
<source>:28:18: note: 'dumb_array' is not derived from 'std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
28 | std::swap(*this, rhs);
| ~~~~~~~~~^~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/uses_allocator_args.h:38,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/bits/memory_resource.h:41,
from /opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/string:58:
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/tuple:2169:5: note: candidate: 'template<class ... _Elements> constexpr typename std::enable_if<std::__and_<std::__is_swappable<_Elements>...>::value>::type std::swap(tuple<_UTypes ...>&, tuple<_UTypes ...>&)'
2169 | swap(tuple<_Elements...>& __x, tuple<_Elements...>& __y)
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/tuple:2169:5: note: template argument deduction/substitution failed:
<source>:28:18: note: 'dumb_array' is not derived from 'std::tuple<_UTypes ...>'
28 | std::swap(*this, rhs);
| ~~~~~~~~~^~~~~~~~~~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/tuple:2187:5: note: candidate: 'template<class ... _Elements> constexpr typename std::enable_if<(! std::__and_<std::__is_swappable<_Elements>...>::value)>::type std::swap(tuple<_UTypes ...>&, tuple<_UTypes ...>&)' (deleted)
2187 | swap(tuple<_Elements...>&, tuple<_Elements...>&) = delete;
| ^~~~
/opt/compiler-explorer/gcc-trunk-20230709/include/c++/14.0.0/tuple:2187:5: note: template argument deduction/substitution failed:
<source>:28:18: note: 'dumb_array' is not derived from 'std::tuple<_UTypes ...>'
28 | std::swap(*this, rhs);
| ~~~~~~~~~^~~~~~~~~~~~
Compiler returned: 1
In case of using friend swap
function everything is fine.