Почему std :: shuffle принимает ссылку rvalue?

Поскольку C++ 11, std::shuffle() принимает ссылку rvalue на генератор случайных бит:

template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g);

И поэтому я могу назвать это так:

std::vector<int> v = {...};
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);

Это показывает ошибку в моем понимании C++, которую я не смог удовлетворить сегодня утром: что получается, используя ссылку rvalue здесь? Другими словами, почему это не

template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG& g);

Ответ 1

Это ссылка для пересылки, а не ссылка rvalue. Они имеют внешне похожий синтаксис, но могут быть дифференцированы базовым типом, являющимся вычисленным параметром шаблона.

Ваша предложенная альтернатива не будет компилироваться, если для третьего аргумента задано rvalue, тогда как ссылка пересылки позволяет использовать любую категорию значений аргумента.

Используя пример cppreference, это означает, что у вас есть оба варианта:

std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);

а также

std::shuffle(v.begin(), v.end(), std::mt19937(rd()));