要求
std::tuple
による任意のユーザー定義のタプル TUPLE_TYPE
型の tuple
オブジェクトに対し任意のユーザー定義のファンクター FUNCTOR_TYPE
型の functor
オブジェクトを適用する apply
関数を作成したい。
期待される使用例
auto tuple = std::make_tuple( 1, 2.3f, '4', "567" );
auto functor = []( auto value ){ std::cout << value << "\n"; };
apply( tuple, functor ); // <-- これを作りたい
期待される結果
この apply に期待される結果として次の出力を得たい。
1
2.3
4
567
そのような apply
の作り方
#include <cstddef>
#include <tuple>
#include <utility>
template < typename TUPLE_TYPE, typename FUNCTOR_TYPE, std::size_t ... INDICES >
void apply( TUPLE_TYPE&& tuple, FUNCTOR_TYPE&& functor, std::index_sequence< INDICES ... > )
{
using swallow = int[];
(void) swallow { 1, ( functor( std::get< INDICES >( std::forward< TUPLE_TYPE >( tuple ) ) ), void(), int {} ) ... };
}
template < typename TUPLE_TYPE, typename FUNCTOR_TYPE >
void apply( TUPLE_TYPE&& tuple, FUNCTOR_TYPE&& functor )
{
constexpr std::size_t SIZE = std::tuple_size< std::remove_reference_t< TUPLE_TYPE > >::value;
apply( std::forward< TUPLE_TYPE >( tuple ), std::forward< FUNCTOR_TYPE >( functor ), std::make_index_sequence< SIZE >{ } );
}
使い方
#include <iostream>
auto main() -> int
{
apply
( std::make_tuple( 1, 2.3f, '4', "567" )
, []( auto value ) { std::cout << value << "\n"; }
);
}
実行結果
1
2.3
4
567
Wandbox
ポイント
- C++14 の機能 :
std::make_index_sequence
,std::remove_reference_t
- C++11 の機能 : variadic-templates, r-value-references,
constexpr
,auto
,std::tuple_size
,std::forward
トリック
-
apple
のswallow
型(つまりint[]
型)のブレース初期化により、functor( std::get< INDEX >( tuple ) )
的な動作についてINDEX
をINDICES ...
について一挙に定義する。- この時、C++ では
void[]
型では扱えないのでint[]
としている。- よって、
int
型を作らなくてはならないからswallow
で初期化される個々の要素は, int{ }
(カンマ演算子+int
オブジェクトの生成)を付加し、結果がint
型となるようにしている。- このトリックのために
INDICES
が展開された際に完全にf()
と, int { }
だけではf()
がint
を返すと困るので間に, void()
も挟む。
- このトリックのために
- よって、
-
swallow
は生成された後にそれ自体はapply
の中では使わないのでコンパイラーが warning を出す。そこで(void)
にキャストしておくことで不要な警告が出で煩わされないようにしている。 - 空っぽの
int[] { }
を定義しないためにダミーで先頭に1
を入れている。
- この時、C++ では
Reference
-
StackExchange - CODE REVIEW - std::tuple foreach implementation - Answer ( Louis Dionne )
- 今回の記事はこの Answer を元にしています。