126

BoostタプルライブラリまたはTR1の標準ライブラリのいずれかで、C ++でタプルを使用している人がいないように見えるのはなぜですか?私は多くのC++コードを読んだことがあり、タプルの使用を目にすることはめったにありませんが、タプルが多くの問題を解決する場所(通常は関数から複数の値を返す)をよく目にします。

タプルを使用すると、次のようなあらゆる種類のクールなことができます。

tie(a,b) = make_tuple(b,a); //swap a and b

それは確かにこれよりも優れています:

temp=a;
a=b;
b=temp;

もちろん、いつでもこれを行うことができます:

swap(a,b);

しかし、3つの値を回転させたい場合はどうでしょうか。タプルを使用してこれを行うことができます。

tie(a,b,c) = make_tuple(b,c,a);

タプルを使用すると、関数から複数の変数を返すのもはるかに簡単になります。これは、値を交換するよりもはるかに一般的なケースです。参照を使用して値を返すことは、確かにあまり洗練されていません。

私が考えていないタプルの大きな欠点はありますか?そうでない場合、なぜそれらはめったに使用されないのですか?彼らは遅いですか?それとも、人々が彼らに慣れていないというだけですか?タプルを使用するのは良い考えですか?

4

12 に答える 12

125

皮肉な答えは、多くの人がC ++でプログラミングしているが、より高いレベルの機能を理解および/または使用していないということです。許可されていないことが原因の場合もありますが、多くの場合、単に試行しない(または理解しない)だけです。

ブーストではない例として:何人の人々がにある機能を使用してい<algorithm>ますか?

言い換えれば、多くのC ++プログラマーは、C ++コンパイラーを使用する単純なCプログラマーであり、おそらくstd::vectorstd::listです。boost::tupleこれが、の使用が一般的でない理由の1つです。

于 2009-05-13T00:00:07.107 に答える
43

まだ標準ではないからです。非標準のものには、はるかに高いハードルがあります。ブーストのピースは、プログラマーがそれらを求めていたために人気がありました。(hash_mapが頭に浮かぶ)。しかし、タプルは便利ですが、人々がそれを気にするほどの圧倒的で明確な勝利ではありません。

于 2009-05-12T22:10:53.540 に答える
23

C ++タプル構文は、ほとんどの人が望むよりもかなり冗長になる可能性があります。

検討:

typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple;

したがって、タプルを広範囲に使用したい場合は、どこでもタプルtypedefを取得するか、どこでも厄介な長い型名を取得します。タプルが好きです。必要に応じて使用します。ただし、通常は、N要素のインデックスやマルチマップを使用して範囲イテレータのペアを結び付ける場合など、いくつかの状況に限定されます。そして、それは通常、非常に限られた範囲にあります。

HaskellやPythonのようなものと比較すると、すべて非常に醜くてハッキーに見えます。C ++ 0xがここに到達し、「auto」キーワードを取得すると、タプルはより魅力的に見え始めます。

タプルの有用性は、タプルの宣言、パック、およびアンパックに必要なキーストロークの数に反比例します。

于 2009-05-12T23:17:40.310 に答える
10

私にとって、それは習慣です。タプルは私にとって新しい問題を解決しません。私がすでにうまく処理できるのはほんのわずかです。値の交換は、昔ながらの方法でも簡単に感じられます。さらに重要なことに、私は「より良い」交換方法についてはあまり考えていません。そのままで十分です。

個人的には、タプルは複数の値を返すための優れたソリューションではないと思います。sの仕事のように聞こえますstruct

于 2009-05-13T00:26:38.977 に答える
8

しかし、3つの値を回転させたい場合はどうでしょうか。

swap(a,b);
swap(b,c);  // I knew those permutation theory lectures would come in handy.

OK、つまり4などの値を使用すると、最終的にnタプルはn-1スワップよりも少ないコードになります。また、デフォルトのスワップでは、3サイクルのテンプレートを自分で実装した場合の4つではなく、6つの割り当てが行われますが、コンパイラーが単純な型でそれを解決することを期待しています。

たとえば、スワップが扱いにくい、または不適切なシナリオを考え出すことができます。

tie(a,b,c) = make_tuple(b*c,a*c,a*b);

開梱するのは少し厄介です。

ただし、ポイントは、タプルが適している最も一般的な状況に対処するための既知の方法があるため、タプルを取り上げる緊急性はそれほど高くありません。他に何もないとしても、私はそれを確信していません:

tie(a,b,c) = make_tuple(b,c,a);

6つのコピーを実行しないため、一部のタイプにはまったく不適切です(コレクションが最も明白です)。タプルは「大きな」タイプには適していないと言って、遠慮なく私を説得してください:-)

複数の値を返す場合、値が互換性のないタイプである場合はタプルが最適ですが、呼び出し元が間違った順序で取得する可能性がある場合、タプルが気に入らない人もいます。一部の人々は、複数の戻り値をまったく好まないので、それらを簡単にすることによってそれらの使用を奨励したくありません。一部の人々は、入力パラメータと出力パラメータに名前付き構造を好むだけで、おそらく野球のバットでタプルを使用するように説得することはできませんでした。味の説明はありません。

于 2009-05-13T00:16:47.343 に答える
8

多くの人が指摘しているように、タプルは他の機能ほど有用ではありません。

  1. 交換と回転のギミックは単なるギミックです。それらは、これまでに見たことがない人にはまったく混乱します。ほとんどの人がそうであるため、これらの仕掛けはソフトウェアエンジニアリングの実践としては不十分です。

  2. タプルを使用して複数の値を返すことは、他の方法よりも自己文書化がはるかに少なくなります。名前付きの型を返すか、名前付きの参照を使用します。この自己文書化がなければ、戻り値が相互に変換可能であり、賢明でない場合、戻り値の順序を混乱させるのは簡単です。

于 2012-12-25T05:45:46.030 に答える
6

誰もがブーストを使用できるわけではなく、TR1はまだ広く利用可能ではありません。

于 2009-05-12T23:44:15.320 に答える
5

組み込みシステムでC++を使用する場合、Boostライブラリのプルは複雑になります。それらは互いに結合するため、ライブラリのサイズが大きくなります。タプルの代わりにデータ構造を返すか、パラメーターの受け渡しを使用します。Pythonでタプルを返す場合、データ構造は戻り値の順序とタイプになり、明示的ではありません。

于 2009-05-13T00:36:34.733 に答える
5

適切に設計されたコードは通常それらを必要としないため、それらを目にすることはめったにありません。匿名の構造体を使用する方が名前付きの構造体を使用するよりも優れている場合はほとんどありません。すべてのタプルが実際に表すのは匿名の構造体であるため、ほとんどの状況でほとんどのコーダーは本物を使用します。

タプルリターンが意味をなす関数「f」があるとします。原則として、このような関数は通常、失敗する可能性があるほど複雑です。

「f」が失敗する可能性がある場合は、ステータスを返す必要があります。結局のところ、呼び出し元が失敗を検出するためにすべてのパラメーターを検査する必要はありません。「f」はおそらくパターンに適合します。

struct ReturnInts ( int y,z; }
bool f(int x, ReturnInts& vals);

int x = 0;
ReturnInts vals;
if(!f(x, vals)) {
    ..report error..
    ..error handling/return...
}

それはきれいではありませんが、代替案がどれほど醜いかを見てください。ステータス値はまだ必要ですが、コードは読みやすくなく、短くもありません。タプルで1コピーのコストがかかるので、おそらくそれも遅くなります。

std::tuple<int, int, bool> f(int x);
int x = 0;
std::tuple<int, int, bool> result = f(x); // or "auto result = f(x)"
if(!result.get<2>()) {
    ... report error, error handling ...
}

もう1つの重大な欠点は、ここに隠されています。「ReturnInts」を使用すると、「f」のインターフェイスを変更せずに「ReturnInts」を変更することで、「f」の戻り値を変更できます。タプルソリューションはその重要な機能を提供しないため、どのライブラリコードに対しても劣った答えになります。

于 2012-12-30T02:10:41.217 に答える
3

確かにタプルは便利ですが、前述のように、実際に使用する前に、少しオーバーヘッドがあり、1つか2つのハードルを飛び越えなければなりません。

プログラムが複数の値を返すか、複数の値を交換する必要がある場所を一貫して見つける場合は、タプルルートを使用する価値があるかもしれませんが、それ以外の場合は、従来の方法で行う方が簡単な場合があります。

一般的に言って、すべての人がすでにBoostをインストールしているわけではありません。また、Boostをダウンロードして、タプル機能のためだけにBoostを使用するようにインクルードディレクトリを構成するという面倒な作業は絶対にありません。すでにBoostを使用している人は、Boost以外のユーザーよりもプログラムでタプルの使用を見つける可能性が高く、他の言語(Pythonが頭に浮かぶ)からの移民はタプルの不足に単に腹を立てる可能性が高いことがわかると思います。タプルサポートを追加する方法を探求するよりもC++で。

于 2009-05-12T23:32:04.250 に答える
1

データストアは、aと配列std::tupleの両方の中で最悪の特性を持っているため。structすべてのアクセスはn番目の位置に基づいていますが、ループtupleを使用して反復することはできません。for

したがって、の要素tupleが概念的に配列である場合は配列を使用し、要素が概念的に配列でない場合は、構造体(要素に名前が付けられている)の方が保守しやすくなります。(a.lastnameより説明的ですstd::get<1>(a))。

これにより、OPによって言及された変換がタプルの唯一の実行可能なユースケースとして残ります。

于 2017-07-27T08:29:43.833 に答える
0

多くの人がBoost.Tupleの代わりにBoost.AnyとBoost.Variant(いくつかのエンジニアリングを含む)を使用しているように感じます。

于 2009-05-12T23:04:47.383 に答える