Search code examples
c++c++-conceptsrvalue-reference

Different behavior when using the typetraits directly vs in a concept for r-value references


Consider the following code snippet.

template <typename T>
concept IsRValue = std::is_rvalue_reference_v<T>;

void funTakingRValues(IsRValue auto&& val)
{
    std::cout << val << std::endl;
}

int main()
{
    auto && x = 5;
    std::cout << "Is rvalue reference = " << std::is_rvalue_reference_v<decltype(x)> << std::endl;
    funTakingRValues(std::forward<decltype(x)>(x));
}

In this case x is considered an r-value reference based on the cout statement result. But the constraint IsRValue which relies on the same type trait is not satisfied. What is happening?


Solution

  • As stated by HolyBlackCat, T is deduced as an int since auto is qualified by &&. To fix your concept you can add the rvalue reference back to T like

    template <typename T>
    concept IsRValue = std::is_rvalue_reference_v<std::add_rvalue_reference_t<T>>;
    

    and now if T is an int then it becomes int&& and it passes the trait. If an lvalue int is passed to the function then T gets deduced to int & and adding an rvalue reference to that still results in int& because of the reference collapse rules and the function will error out.

    You can see this working in this live example.