2

Here is an algorithm std::shuffle from https://en.cppreference.com/w/cpp/algorithm/random_shuffle:

 template<class RandomIt, class URBG>
 void shuffle(RandomIt first, RandomIt last, URBG&& g)
 {
     typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
     typedef std::uniform_int_distribution<diff_t> distr_t;
     typedef typename distr_t::param_type param_t;

     distr_t D;
     diff_t n = last - first;
     for (diff_t i = n-1; i > 0; --i) {
         using std::swap;
         swap(first[i], first[D(g, param_t(0, i))]);
     }
 }
  • Why the algorithm takes a forwarding reference to the generator URGB&& g? As long as it didn't use std::forward<URGB>(g) to forward the generator either as an l-value or as an r-value?

  • Why the using declaration is inside of loop body rather than outside of it? Does leaving it inside (iteratively) affects performance? Thank you!

Itachi Uchiwa
  • 3,044
  • 12
  • 26

1 Answers1

2

Why the algorithm takes a forwarding reference to the generator URGB&& g?

Because the algorithm does not want to copy the generator, it passes by reference, and in order to be able to accept the temporary rvalue generator, it takes a forwarding reference.

As long as it didn't use std::forward<URGB>(g) to forward the generator either as an l-value or as an r-value?

Because the generator is not only invoked once. If the rvalue is forwarded, its state may be changed before the next invoked.

Why the using declaration is inside of loop body rather than outside of it?

This is a so-called std::swap two-step, and it is idiomatic to use unqualified swap immediately after using std::swap. The advantage of putting it inside the loop is that its scope is limited to the loop, and putting it outside may pollute the naming.

Does leaving it inside (iteratively) affects performance?

No.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • 1
    Wht you mean with "`std::swap` two step"? so do you mean: `using std::swap; for(;;){ swap(x, y);}` aren't the same as `for(;;){ using std::swap; swap(x, y);}`? – Itachi Uchiwa Nov 11 '21 at 13:21
  • @ItachiUchiwa. They are the same. But the latter is an idiom form. – 康桓瑋 Nov 11 '21 at 13:30
  • Would you tell me about the latter? I've not heard about it. – Itachi Uchiwa Nov 11 '21 at 14:16
  • I know this although I don't know its name "two-steps swap" but you didn't get my point. I said: why not using 'two-steps swap' in a way putting the using declaration outside of the loop body: `using std::swap; for(){ swap(x, y);}` rather than inside loop body: `for(){ using std::swap; swap(x, y);}` – Itachi Uchiwa Nov 11 '21 at 14:48
  • @ItachiUchiwa. As I said, this is just idiomatic style. You can also put it on the outside. The advantage of putting it inside the for-loop is that its scope is only inside the for-loop, and putting it outside the for loop [may pollute the naming](https://godbolt.org/z/Pcd1zTa1K). – 康桓瑋 Nov 11 '21 at 15:02
  • This usage of `&&` I think is called a universal reference (as opposed to a forwarding reference, even though to the compiler they are the same thing) and it means that if you call the function passing an l-value generator the generator will be called as an l-value, but if you call it with an r-value then the generator will only be called as an r-value – SirGuy Nov 11 '21 at 15:11
  • @SirGuy. The current C++ standard term is [forwarding reference](https://stackoverflow.com/questions/39552272/is-there-a-difference-between-universal-references-and-forwarding-references). – 康桓瑋 Nov 11 '21 at 15:14