#include <utility>
template<typename T>
concept IsWritable = requires(T& obj)
{
obj = 0;
};
template<typename T>
void f(T&)
{}
int main()
{
static_assert(IsWritable<int&&>); // ok
int n = 0;
f(std::move(n)); // error
}
GCC error message:
error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type
'std::remove_reference<int&>::type' {aka 'int'}
Why can't I bind an lvalue-reference to an rvalue while a concept can?
Given
template<typename T>
void f(T&)
{}
the line
f(std::move(n)); // error
must error, because you're trying to pass an rvalue argument, std::move(n)
, to a lvalue reference parameter, T&
.
As regards the concept, notice that there's no argument-parameter pair on the value level. And it's on the value level that talking about rvalue/lvalue-ness makes sense (after all, those are called value categories).
There's an argument-parameter pair on the type level, though: you're explicitly passing the int&&
template argument to IsWritable
's template argument T
, so the T&
will be int&& &
, which is int&
, because normal reference collpasing applies (it doesn't just apply to universal references).