1. ホーム
  2. c++

[解決済み] std::getはどのように動作するのですか?

2022-03-07 20:23:41

質問

を作ろうとした結果 std::get<N> <サブ (std::tuple) というメソッドが、コンパイラによってどのように実装されているのか、私自身はあまりよく分かっていません。私が知っているのは std::tuple には、このようなコンストラクタがあります。

tuple(Args&&... args);

しかし、具体的にどのような args... が割り当てられているのでしょうか?を知るために役立つと思います。 std::get は、引数をアクセスするためにどこかに配置する必要があるため、動作します...。

どのように解決するのですか?

以下は tuple -のようなクラスです。

まず、整数の列を表現するためのメタプログラミングの定型文をいくつか紹介します。

template<int...> struct seq {};
template<int max, int... s> struct make_seq:make_seq< max-1, max-1, s... > {};
template<int... s> struct make_seq<0, s...> {
  typedef seq<s...> type;
};
template<int max> using MakeSeq = typename make_seq<max>::type;

次に、実際にデータを格納するタグ付きクラスです。

template<int x, typename Arg>
struct foo_storage {
  Arg data;
};

このタグ付けの手法は、コンパイル時にデータを何らかのタグ(この場合は整数)と関連付けたいときによく使われるパターンです。 このタグ( int ここでは)通常、ストレージのどこにも使用されません。

foo_helper は、シーケンスと引数のセットを、複数の foo_storage そして、それらを線形に継承します。 これはよくあるパターンで、これをたくさんやっていると、結局これをやってくれるメタプログラミングのツールを作ることになります。

template<typename Seq, typename... Args>
struct foo_helper {};
template<int s0, int... s, typename A0, typename... Args>
struct foo_helper<seq<s0, s...>, A0, Args...>:
  foo_storage<s0, A0>,
  foo_helper<seq<s...>, Args...>
{};

私の粗悪品 tuple の型があります。 foo で、一連のインデックスと引数からなるパッケージを作成し、 上記のヘルパーに渡します。 そして、ヘルパーは親クラスを保持するタグ付きデータの束を作成します。

template<typename... Args>
struct foo: foo_helper< MakeSeq<sizeof...(Args)>, Args... > {};

の本文からすべてを削除しました。 foo を実装するのに必要ないからです。 get .

get は非常にシンプルです。タプル型ではなくストレージ型をとり、明示的に template 引数 N がどのようなものであるかを曖昧にします。 foo_storage<n, T> にアクセスすることになります。 ストレージの型がわかったので、あとはデータフィールドを返すだけです。

template<int N, typename T>
T& get( foo_storage<N, T>& f )
 { return f.data; }
template<int N, typename T>
T const& get( foo_storage<N, T> const& f )
 { return f.data; }

C++言語のオーバーロード機構を利用して、重い仕事をこなしているのです。 あるクラスのインスタンスで関数を呼び出すと、そのインスタンスと親クラスのそれぞれを調べて、一致させることができるかどうかを確認します。 このとき N が固定されている場合、有効な引数となる親クラスは1つだけなので、親クラス(つまりは T が自動的に推論されます。

そして最後に、基本的なテストコードをいくつか紹介します。

#include <iostream>

int main() {
  foo<int, double> f;
  get<0>( f ) = 7;
  get<1>( f ) = 3.14;
  std::cout << get<0>(f) << "," << get<1>(f) << "\n";
}