Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++20 concepts: int not swappable_with int

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;
}
like image 495
Topological Sort Avatar asked Jun 09 '20 13:06

Topological Sort


2 Answers

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);.

like image 196
Daniel Langr Avatar answered Nov 10 '22 10:11

Daniel Langr


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 ints.

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.

like image 9
Yakk - Adam Nevraumont Avatar answered Nov 10 '22 11:11

Yakk - Adam Nevraumont