Edited at

同じ型が入った std::tuple を楽に書く方法

More than 1 year has passed since last update.

std::tuple<double, double, double, double>とか書くのが面倒なので。


結論

以下のような構造体を定義する。

#include <tuple>


template <class T, std::size_t Size, class... Args>
struct HomoTupleStruct
{
typedef typename HomoTupleStruct<T, Size - 1, Args..., T>::type type;
};

template <class T, class... Args>
struct HomoTupleStruct<T, 0, Args...>
{
typedef std::tuple<Args...> type;
};

template <class T, std::size_t Size>
using HomoTuple = typename HomoTupleStruct<T, Size>::type;

利用例は以下の通り。

#include <type_traits>

#include <cassert>

static_assert(std::is_same<HomoTuple<int, 1>,
std::tuple<int>>::value, "orz");
static_assert(std::is_same<HomoTuple<double, 2>,
std::tuple<double, double>>::value, "orz");
static_assert(std::is_same<HomoTuple<int&, 3>,
std::tuple<int&, int&, int&>>::value, "orz");

int main()
{
HomoTuple<int, 5> homoTuple1 = std::make_tuple(3, 1, 4, 1, 5);
HomoTuple<int, 3> homoTuple2 = std::make_tuple(9, 2, 6);
HomoTuple<int, 8> homoTuple3 = std::tuple_cat(homoTuple1, homoTuple2);

assert(std::get<6>(homoTuple3) == 2);
}


備考

std::array は tuple のように扱える(std::tuple_size, std::tuple_element, std::get が特殊化されている)ので、大抵の用途においては std::array で十分だったりする。以下は clang++ で動くコードである。

int main() {

std::array<double, 4> rgba {{0.1, 0.2, 0.3, 0.4}};

double r, g, b;
std::tie(r, g, b, std::ignore) = rgba;
std::cout << r << ", " << g << ", " << b << '\n';
std::cout << std::get<3>(rgba) << '\n';

// std::array -> HomoTuple
HomoTuple<double, 4> rgba_tuple = rgba;
}

ただし、std::tie しようとしたりすると g++ ではコンパイルが通らなくなる (Wandbox, gcc HEAD 7.0.0 20161219) 1 ので、同じ型の入った std::tuple を使わなければいけない場面はありそう。Boost.fusion も考慮に入れるべきかも。

std::tuple から std::array への変換については下記ページが参考になる。

int main() {

HomoTuple<double, 4> rgba_tuple = {0.1, 0.2, 0.3, 0.4};
std::array<double, 4> rgba = to_array(rgba_tuple); // 上記ページ参照
for (auto && x : rgba)
std::cout << x << ' ';
}
std::cout << '\n';
}





  1. std::array の tuple インターフェースについては C++11 規格ドラフト (N3337) の "23.3.2.9 Tuple interface to class template array [array.tuple]" の項に記載されている。arraytie についての g++(あるいは clang++)の実装が規格違反(あるいはどっちも ok)なのかどうかはよくわかんなかったです……。