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