LoginSignup
5
5

More than 5 years have passed since last update.

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

Last updated at Posted at 2012-12-26

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)なのかどうかはよくわかんなかったです……。 

5
5
0

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
5
5