Я читал страницу 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
неправильной? Я что-то пропустил?