Search code examples
c++standardsc++20rvalue-referencec++-concepts

Why can't I bind an lvalue-reference to an rvalue while a concept can?


#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?


Solution

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