貝柱が何かをする所

貝柱が何かをする所です、C++/Perl/その他諸々

Template Parameter PackをReverseする

まえがき

C++ではもはやおなじみになったTemplate Parameter Pack。今回はこれについてだ。

例えば、以下のように引数に与えられた値を出力するだけの関数があるとする。

template<typename Ty>
void shower(Ty head) {
	std::cout << head << std::endl;
}
template<typename Ty, typename... Ts>
void shower(Ty head, Ts... tail) {
	std::cout << head;
	shower(tail...);
}

これに対して、与えた逆順に出力してほしいものとする。
パラメータパックの逆展開だ。

コード

これには、stackoverflowの記事が大変参考になった。
c++ - How to reverse the order of arguments of a variadic template function? - Stack Overflow

これを基に以下のようにコードをおこした。

#include <iostream>

template<typename Ty>
void shower(Ty head) {
	std::cout << head << std::endl;
}
template<typename Ty, typename... Ts>
void shower(Ty head, Ts... tail) {
	std::cout << head;
	shower(tail...);
}

template<typename... Tn>
struct revert;

template<>
struct revert<>
{
	template<typename... Un>
	static void apply(Un const&... un) {
		shower(un...);
	}
};

template<typename Ty, typename... Ts>
struct revert<Ty, Ts...>
{
	template<typename ...Un>
	static void apply(Ty const& t, Ts const&... tail, Un const&... un) {
		revert<Ts...>::apply(tail..., t, un...);
	}
};

template<typename Ty, typename... Ts>
void reverse_shower(Ty const& val, Ts const&... tail) {
	revert<Ts...>::apply(tail..., val);
}

int main(void) {
	reverse_shower(1, 2, 3, 4, 5);

	/*
	reverse_shower<int, int ,int ,int ,int>( 1, 2, 3, 4, 5 )
	revert<int, int, int, int>::apply(2, 3, 4, 5, 1)
	revert<int, int, int>::apply(3, 4, 5, 2, 1)
	revert<int ,int>::apply(4, 5, 3, 2, 1)
	revert<int>::apply(5, 4, 3, 2, 1)
	revert<>::apply(5, 4, 3, 2, 1)
	shower(5, 4, 3, 2, 1)
	*/

	return 0;
}

非常に美しいテクニックだと思う。
実際に実用に取り入れられるかは分からないが、何かで実践的なコードを書いてみたい。