Я читал страницу cppreference на Constraints и заметил этот пример:
// 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));
};
Я озадачен, почему они используют std::forward. Некоторые пытаются поддерживать ссылочные типы в параметрах шаблона? Разве мы не хотим вызывать swap с lvalues и не будут ли выражения forward быть rvalues, когда T и U являются скалярными (не ссылочными) типами?
Например, я ожидал бы, что эта программа завершится с ошибкой при реализации Swappable:
#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);
}
К сожалению, g++ 7.1.0 дает мне внутреннюю ошибку компилятора которая не проливает свет на это.
Здесь оба T и U должны быть MyType, а std::forward<T>(t) должен возвращать MyType&&, который не может быть передан моей функции swap.
Является ли эта реализация Swappable неправильной? Я что-то пропустил?