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