LoginSignup
4
4

More than 5 years have passed since last update.

c++ tuple に対するmap風の関数適用

Last updated at Posted at 2018-04-03

はじめに

この記事では、ある要求に対して、筆者が気づいた1つの解決策を載せています。もっと拡張できる!や、全く別のアプローチがある!などの発見をぜひ楽しんでください。

要求

同一の型を格納したコレクションに対して、そのすべての要素に関数を適用したい。

コレクション

タイトルにあるように、サンプルとなるコレクションをstd::tuple で定義してみる。

enum class color { r, g, b };
const auto list = std::make_tuple( 
    color::r, 
    color::g, 
    color::b );

std::array のインスタンス化には必要な要素数の明示的な記述は、std::tuple では必要ない。これは、プログラムの拡張性を維持したい場合に嬉しい性質である。また、要素へのアクセスにはアクセサ(std::get)を通すため、不正な操作を防止しやすい。

実装

早速、map “風”の関数適用の実装をお見せしたい。

アイデアはとても簡単で、tuple の要素へアクセスするための std::get に渡すテンプレートパラメータを、再帰呼び出しと部分特殊化によって満たす。ただし、注意したいのは、そのパラメータとなるインデックスが降順に適用されるところである。

template< typename T, size_t N = std::tuple_size<T>::value >
struct tuple_map
{
    static void apply( const T& t, const std::function<void( const typename std::tuple_element<0, T>::type&, const size_t )>& map_func )
    {
        map_func( std::get<N-1>( t ), N-1 );
        return tuple_map<T, N-1>::apply( t, map_func );
    }
};

template< typename T >
struct tuple_map<T, 0>
{
    static void apply( const T&, const std::function<void( const typename std::tuple_element<0, T>::type&, const size_t )>& ) {}
};

クラス名、関数名がもし適切ではないとしてもご容赦いただきたい。(ご助言、お待ちしております。)map_func 関数に対して、tuple 要素のインデックスを渡すことができるのも、この tuple_map の特徴である。

前提にあるように、tuple の要素はすべて同一の型であるので、map_func の型は決め打ちできる。(tuple の最初の要素の型を基準にする。)これを満たさない場合は、コンパイルエラーとなる。

使用例

前述のコレクションに対して使用する。

tuple_map<decltype(list)>::apply( list, []( const color& c, const size_t index ) { std::cout << index << static_cast<uint32_t>(c) << std::endl; } );

インデックスを降順に走査するので、b, g, r の順に値が出力される。

おわりに

筆者は皆さんと同様、要求に対してやや大げさな実装をしたような感覚を否めない。しかし、冗長なコードをなくし、スッキリさせることができるのは間違いない。tuple と template を使った1つの遊び、楽しんでいただけただろうか。

4
4
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4