A very simple but useful algorithm: rotate the values of a given number of variables in-place to the left so that the first variable gets the value of the second, the second gets the value of the third, etc... and the last variable gets the value of the first one.
#include <type_traits>
#include <utility>
template<typename Head, typename... Tail>
struct are_same:
std::conjunction<std::is_same<Head, Tail>...>
{};
template<typename T, typename... Args>
auto rotate_left_inner(T& first, T& second, Args&... args)
-> T&
{
first = std::move(second);
if constexpr (sizeof...(Args) == 0) {
return second;
} else {
return rotate_left_inner(second, args...);
}
}
template<typename Head, typename... Tail>
auto rotate_left(Head& first, Tail&... args)
-> void
{
static_assert(are_same<Head, Tail...>::value,
"elements passed to rotate_left shall have the same type");
if constexpr (sizeof...(Tail) > 0) {
auto tmp = std::move(first);
auto& last = rotate_left_inner(first, args...);
last = std::move(tmp);
}
}
This function can be used as follows:
int a=0, b=1, c=2, d=3, d=4;
rotate_left(a, c, e);
rotate_left(b, d);
// Now (a, b, c, d, e) = (2, 3, 4, 1, 0)
The code above generated the same assembly than the hand-rolled version when I gave it five integers to rotate in the compiler explorer, with both GCC and Clang.
I wanted to make a companion rotate_right
function, but repeatedly finding the last element of a template parameter pack is not as easy, so the easiest solution for a programmer is to pass the variables to rotate to rotate_left
in reverse order.
Do you see any way to improve this simple algorithm? Anything that I might be missing?
compiler explorer
is? \$\endgroup\$