この前の問題2が少し気になっていた。
交互に要素を取ることで、2つのリストを結合する関数を記述せよ。例えば [a, b, c]と[1, 2, 3]という2つのリストを与えると、関数は [a, 1, b, 2, c, 3]を返す。
というやつである。
というわけで、std::array<char, 3>
とstd::array<int, 3>
を受け取ってstd::tuple<char, int, char, int, char, int>
を返す関数を書いた。
std::tuple_cat
が非常に便利だということがわかった。また、単一の関数で再帰しようとしたところ、毎再帰ステップで返す型が異なるのでエラーが出た。あまり色々試す前にとっとと諦めてしまったので、また思い出したときに書いてみよう。
基本的には、
combine (x:xs) (y:ys) = combine xs ys ++ [x, y]
のようなことをしている。順番が逆だが。
#include <tuple> #include <array> #include <type_traits> template<typename ... T_args> struct join; template<template<typename ... T> class pack, typename T, typename ... T_args> struct join<T, pack<T_args...>> { typedef pack<T, T_args...> type; }; static_assert(std::is_same<typename join<int, std::tuple<char, double>>::type, std::tuple<int, char, double>>::value, "join"); template<typename T1, typename T2, std::size_t N, typename ... T_args> struct combine_type_impl { typedef typename combine_type_impl<T1, T2, N-1, typename join<T1, typename join<T2, std::tuple<T_args...>>::type>::type>::type type; }; template<typename T1, typename T2, std::size_t N, typename ... T_args> struct combine_type_impl<T1, T2, N, std::tuple<T_args...>> { typedef typename combine_type_impl<T1, T2, N-1, typename join<T1, typename join<T2, std::tuple<T_args...>>::type>::type>::type type; }; template<typename T1, typename T2, typename ... T_args> struct combine_type_impl<T1, T2, 0, std::tuple<T_args...>> { typedef typename join<T1, typename join<T2, std::tuple<T_args...>>::type>::type type; }; template<typename T1, typename T2, std::size_t N> struct combine_type { typedef typename combine_type_impl<T1, T2, N-1>::type type; }; static_assert(std::is_same<typename combine_type<char, int, 3>::type, std::tuple<char, int, char, int, char, int>>::value, "combine_type"); template<typename T1, typename T2, std::size_t N, std::size_t M> struct combine_impl { static typename combine_type<T1, T2, M+1>::type invoke(std::array<T1, N> lhs, std::array<T2, N> rhs) { return std::tuple_cat(combine_impl<T1, T2, N, M-1>::invoke(lhs, rhs), std::make_tuple(lhs[M], rhs[M])); } }; template<typename T1, typename T2, std::size_t N> struct combine_impl<T1, T2, N, 0> { static std::tuple<T1, T2> invoke(std::array<T1, N> lhs, std::array<T2, N> rhs) { return std::make_tuple(lhs[0], rhs[0]); } }; template<typename T1, typename T2, std::size_t N> typename combine_type<T1, T2, N>::type combine(std::array<T1, N> lhs, std::array<T2, N> rhs) { return combine_impl<T1, T2, N, N-1>::invoke(lhs, rhs); } #include <iostream> int main() { constexpr std::array<char, 3> ar1{{'a', 'b', 'c'}}; constexpr std::array<int, 3> ar2{{1, 2, 3}}; typename combine_type<char, int, 3>::type t = combine(ar1, ar2); std::cout << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << ", " << std::get<3>(t) << ", " << std::get<4>(t) << ", " << std::get<5>(t) << std::endl; return 0; }