I'm trying out C++20's concepts, and either std::swappable_with
is undefined (Visual Studio, using /std:c++latest
) or its constraints are not matched by the MCVE below (g++10 using -std=c++2a
) -- that is, int
is not swappable with int
(!). What's the fix for this? If int
can't be swapped with int
, I don't see anything working.
#include <concepts>
template <typename T, typename U>
requires std::swappable_with<T,U>
void mySwap(T& t, U& u)
{
T temp = t; t = u; u = temp;
}
int main()
{
int x, y;
mySwap(x, y);
return 0;
}
std::swappable_with<T, U>
checks whether swap
can be invoked (after using std::swap;
) with arguments std::declval<T>()
and std::declval<U>()
. With T
and U
being int
, both arguments are rvalues, which cannot be bound to std::swap
parameters, since these are (non-const) lvalue references.
You wonder that int
cannot be swapped with int
— that's right, you cannot write std::swap(1, -1);
.
Use std::swappable_with<T&,U&>
- swappable with cares about value category, encoded by reference, as well as type.
You are in effect asking if rvalues of type int
can be swapped. And it says "no"; you cannot swap to rvalue int
s.
This might be confusing, but if you do this:
template <class T, class U>
requires std::swappable_with<T,U>
void mySwap(T&& t, U&& u) {
auto temp = std::forward<T>(t);
t = std::forward<U>(u);
u = std::move(temp);
}
it becomes a bit more natural. Here, we use forwarding references, and the l/rvalue categories of the argument are stored along side the bare types in T
and U
respectively.
Note that the above could permit rvalues to be swapped, if objects of that type are swappable_with
each other.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With