45

C ++ 11でタプルを使用するための良いユースケースは何ですか?たとえば、ローカル構造体を次のように定義する関数があります。

template<typename T, typename CmpF, typename LessF>
void mwquicksort(T *pT, int nitem, const int M, CmpF cmp, LessF less)
{
  struct SI
  {
    int l, r, w;
    SI() {}
    SI(int _l, int _r, int _w) : l(_l), r(_r), w(_w) {}
  } stack[40];

  // etc

SI構造体を。に置き換えることを検討していましたstd::tuple<int,int,int>。これは、便利なコンストラクターと演算子が既に事前定義されているはるかに短い宣言ですが、次の欠点があります。

  • タプル要素は、あいまいな実装定義の構造体に隠されています。Visual Studioはその内容を適切に解釈して表示しますが、タプル要素の値に依存する条件付きブレークポイントを設定することはできません。
  • 個々のタプルフィールド(get<0>(some_tuple))へのアクセスは、構造体要素()へのアクセスよりもはるかに冗長ですs.l
  • 名前でフィールドにアクセスすることは、数値インデックスよりもはるかに有益です(そして短くなります!)。

最後の2つのポイントは、関数によっていくらか対処されtieます。これらの不利な点を考えると、タプルの良いユースケースは何でしょうか?

UPDATE VS2010 SP1デバッガーは次の配列の内容を表示できないことが判明しましたstd::tuple<int, int, int> stack[40]が、構造体でコーディングされている場合は正常に機能します。したがって、決定は基本的に簡単です。値を検査する必要がある場合は、構造体[esp。GDBのようなデバッガーでは重要です]。

4

9 に答える 9

60

関数から複数の値を返す簡単な方法です。

std::tuple<int,int> fun();

結果の値は、次のようにエレガントに使用できます。

int a;
int b;
std::tie(a,b)=fun();
于 2012-04-21T13:48:00.430 に答える
30

まあ、私見ですが、最も重要な部分は汎用コードです。あらゆる種類の構造体で機能する汎用コードを作成することは、タプルで機能する汎用コードを作成するよりもはるかに困難です。たとえば、std::tieあなたが言及した関数は、構造体に対して作成することはほとんど不可能です。

これにより、次のようなことができます。

  • 遅延実行用の関数パラメーターを保存します (例:この質問)
  • 面倒な(解凍)パッキングなしで複数のパラメータを返すstd::tie
  • (同じ型ではない) データ セットを (たとえば、並列実行から) 結合しstd::tuple_catます。

問題は、これらの使用にとどまらないということです。人々はこのリストを拡張して、構造体でははるかに難しいタプルに基づく汎用機能を書くことができます。明日誰かがシリアライゼーションの素晴らしい用途を見つけるかもしれません。

于 2012-04-21T14:03:17.190 に答える
20

tuples のほとんどの使用は、次のものに由来すると思いますstd::tie

bool MyStruct::operator<(MyStruct const &o) const
{
    return std::tie(a, b, c) < std::tie(o.a, o.b, o.c);
}

ここの回答の他の多くの例とともに。ただし、この例は、C++03 で使用されていた方法よりも多くの労力を節約できるため、最も一般的に役立つと思います。

于 2013-04-24T16:06:03.557 に答える
13

を使用したことがありますstd::pairか? 使用する場所の多くは似ていますstd::tupleが、正確に 2 つの値に制限されているわけではありません。

タプルについて挙げた欠点は std::pair にも当てはまります。メンバーにfirstandよりも適切な名前を付けた表現力豊かな型secondが必要な場合もありますが、必要ない場合もあります。同じことがタプルにも当てはまります。

于 2012-05-26T16:11:04.803 に答える
12

いくつかの汎用ライブラリ機能の実装の詳細以外では、タプルの有効な使用法はないと思います。

(可能な) 入力の節約は、結果のコードの自己文書化プロパティの損失を相殺するものではありません。

フィールドの意味のある名前を取り除くだけの構造体の代わりにタプルを使用し、フィールド名を「数値」に置き換えます (std::pair の不適切な概念のように)。

タプルを使用して複数の値を返すことは、名前付きの型を返すか、名前付きの参照を使用するという代替手段よりも自己文書化がはるかに少なくなります。この自己文書化がないと、戻り値が相互に変換可能である場合、戻り値の順序を混同しやすくなります。

于 2012-12-25T05:56:50.000 に答える
2

ミルクの答えについてコメントすることはできないので、別の答えを出す必要があります。

関数型プログラミングを可能にするために、タプルが標準に追加されたと思います。例として、次のようなコード

void my_func(const MyClass& input, MyClass& output1, MyClass& output2, MyClass& output3)
{
   // whatever
}

関数によって返される複数のオブジェクトを持つ唯一の方法であるため、従来の C++ ではどこにでもあります。これは、関数型プログラミングの嫌悪です。今、あなたは書くかもしれません

tuple<MyClass, MyClass, MyClass> my_func(const MyClass& input)
{
   // whatever
   return tuple<MyClass, MyClass, MyClass>(output1, output2, output3);
}

したがって、副作用と可変性を回避し、パイプライン処理を可能にすると同時に、関数のセマンティック強度を維持する機会があります。

于 2016-06-16T21:43:14.823 に答える
2

タプルを使用する他のプログラミング言語との相互運用、および呼び出し元が余分な型を理解する必要なしに複数の値を返す。最初に思いついたのはこの2つです。

于 2012-04-21T13:35:30.970 に答える
0

F.21 : 複数の "out" 値を返すには、 structまたは tupleを返すことをお勧めします。

戻り値にセマンティクスがある名前付き構造体を使用することをお勧めします。それ以外の場合、名前のないタプルは汎用コードで役立ちます。

たとえば、返される値が入力ストリームとエラー コードからの値である場合、これらの値はあまり一緒になりません。それらは、両方を保持するための専用の構造を正当化するほど十分に関連していません。それとは異なり、x と y のペアは Point のような構造になります。

私が参照しているソースは、Herb Sutter の Bjarne Stroustrup によって管理されているので、ある程度信頼できると思います。

于 2020-08-11T17:34:37.413 に答える