私はstd::tie
をあまり考えずに使用しました。それはうまくいくので、私はそれを受け入れました:
auto test()
{
int a, b;
std::tie(a, b) = std::make_Tuple(2, 3);
// a is now 2, b is now 3
return a + b; // 5
}
しかし、これはどのようにブラックマジック動作するのでしょうか? std::tie
によって作成されたテンポラリーは、a
およびb
をどのように変更しますか?これは言語の機能ではなくライブラリの機能であるため、私はこれがより興味深いと感じています。
コアの概念を明確にするために、より基本的な例に減らしましょう。 std::tie
は、より多くの値(のタプル)を返す関数には便利ですが、たった1つの値で問題なく理解できます。
int a;
std::tie(a) = std::make_Tuple(24);
return a; // 24
前進するために知っておくべきこと:
std::tie
は、参照のタプルを構築して返します。std::Tuple<int>
とstd::Tuple<int&>
は2つの完全に異なるクラスであり、それらの間には接続がありません。他のクラスは同じテンプレートstd::Tuple
から生成されたものです。タプルにはoperator=
があり、異なるタイプのタプル(ただし同じ番号)を受け入れます。各メンバーは cppreference から個別に割り当てられます。
template< class... UTypes > Tuple& operator=( const Tuple<UTypes...>& other );
(3)すべてのiについて、
std::get<i>(other)
をstd::get<i>(*this)
に割り当てます。
次のステップは、邪魔になるだけの関数を取り除くことです。そのため、コードを次のように変換できます。
int a;
std::Tuple<int&>{a} = std::Tuple<int>{24};
return a; // 24
次のステップは、これらの構造内で何が起こるかを正確に確認することです。このために、std::Tuple<int>
とT
置換基std::Tuple<int&>
の2種類のTr
置換基を作成します。
struct T { // substituent for std::Tuple<int>
int x;
};
struct Tr { // substituent for std::Tuple<int&>
int& xr;
auto operator=(const T& other)
{
// std::get<I>(*this) = std::get<I>(other);
xr = other.x;
}
};
auto foo()
{
int a;
Tr{a} = T{24};
return a; // 24
}
そして最後に、構造をまとめて削除するのが好きです(まあ、それは100%同等ではありませんが、私たちにとって十分に近く、それを許可するのに十分に明示的です)。
auto foo()
{
int a;
{ // block substituent for temporary variables
// Tr{a}
int& tr_xr = a;
// T{24}
int t_x = 24;
// = (asignement)
tr_xr = t_x;
}
return a; // 24
}
基本的に、std::tie(a)
は、a
へのデータメンバー参照を初期化します。 std::Tuple<int>(24)
は、値24
でデータメンバーを作成し、割り当てにより、最初の構造のデータメンバー参照に24が割り当てられます。ただし、そのデータメンバーはa
にバインドされた参照であるため、基本的に24
をa
に割り当てます。
これはあなたの質問には決して答えませんが、C++ 17は基本的に(コンパイラサポート付き)準備ができているので、それを投稿させてください。将来的には、C++のバージョンも機能します。
C++ 17では、いわゆる構造化バインディングを優先してstd::tie
をスクラッチできます。同じことを行います(まあ、同じではありません、しかし同じ効果があります)ライブラリのサポート、およびalso参照が必要な場合は、参照を取得することができます.
(C++ 17では、コンストラクターは引数の推論を行うので、make_Tuple
も多少余分になっていることに注意してください。)
int a, b;
std::tie(a, b) = std::make_Tuple(2, 3);
// C++17
auto [c, d] = std::make_Tuple(4, 5);
auto [e, f] = std::Tuple(6, 7);
std::Tuple t(8,9); auto& [g, h] = t; // not possible with std::tie