I was reading the cppreference page on Constraints and noticed this example:
// example constraint from the standard library (ranges TS)
template <class T, class U = T>
concept bool Swappable = requires(T t, U u) {
swap(std::forward<T>(t), std::forward<U>(u));
swap(std::forward<U>(u), std::forward<T>(t));
};
I'm puzzled why they're using std::forward. Some attempt to support reference types in the template parameters? Don't we want to call swap with lvalues, and wouldn't the forward expressions be rvalues when T and U are scalar (non-reference) types?
For example, I would expect this program to fail given their Swappable implementation:
#include <utility>
// example constraint from the standard library (ranges TS)
template <class T, class U = T>
concept bool Swappable = requires(T t, U u) {
swap(std::forward<T>(t), std::forward<U>(u));
swap(std::forward<U>(u), std::forward<T>(t));
};
class MyType {};
void swap(MyType&, MyType&) {}
void f(Swappable& x) {}
int main()
{
MyType x;
f(x);
}
Unfortunately g++ 7.1.0 gives me an internal compiler error, which doesn't shed much light on this.
Here both T and U should be MyType, and std::forward<T>(t) should return MyType&&, which can't be passed to my swap function.
Is this implementation of Swappable wrong? Have I missed something?