12

ほとんどのプログラマーと同様に、私は Literate プログラミングの原則を賞賛し、従おうとしていますが、C++ ではstd::pair、無数の一般的なタスクに , を日常的に使用していることに気付きます。しかしstd::pair、私見、文芸プログラミングの卑劣な敵です...

私の要点は、1、2 日前に書いたコードに戻って、std::pair(通常は反復子として) の操作を目にしたときに、「iter->first と iter->second はどういう意味だったの?? ?」。

std::pair他の人も自分のコードを見て同じ疑問を持っていると思いstd::pairます。

4

8 に答える 8

17

std::pair本質的に匿名の列を持つ「ローカル」で本質的に匿名の型を作成する良い方法です。タイプと列に名前を付ける必要がある非常に大きな字句スペースで特定のペアを使用している場合は、struct代わりにプレーンを使用します。

于 2009-06-25T05:13:03.320 に答える
6

これはどう:

struct MyPair : public std::pair < int, std::string >
{
    const int& keyInt() { return first; }
    void keyInt( const int& keyInt ) { first = keyInt; }
    const std::string& valueString() { return second; }
    void valueString( const std::string& valueString ) { second = valueString; }
};

少し冗長ですが、コードでこれを使用すると、読みやすくなる場合があります。次に例を示します。

std::vector < MyPair > listPairs;

std::vector < MyPair >::iterator iterPair( listPairs.begin() );
if ( iterPair->keyInt() == 123 )
    iterPair->valueString( "hello" );

これ以外に、物事をより明確にする特効薬は見当たりません。

于 2009-06-25T14:22:53.393 に答える
2

最近boost::tuple、の代わりに使用していることに気づきましたstd::pair。各メンバーの列挙子を定義できるため、各メンバーが何であるかは明らかです。

typedef boost::tuple<int, int> KeyValueTuple;
enum {
  KEY
  , VALUE
};

void foo (KeyValueTuple & p) {
    p.get<KEY> () = 0;
    p.get<VALUE> () = 0;
}

void bar (int key, int value)
{
  foo (boost:tie (key, value));
}

ところで、このアプローチを使用することに隠れたコストがあるかどうかについてのコメントを歓迎します。

編集:グローバルスコープから名前を削除します。

グローバル名前空間に関する簡単なコメント。一般的に私は使用します:

struct KeyValueTraits
{
  typedef boost::tuple<int, int> Type;
  enum {
    KEY
    , VALUE
  };
};

void foo (KeyValueTuple::Type & p) {
    p.get<KeyValueTuple::KEY> () = 0;
    p.get<KeyValueTuple::VALUE> () = 0;
}

boost::fusionアイデンティティと価値をより緊密に結び付けるのは事実のように見えます。

于 2009-06-25T09:31:00.563 に答える
2

first と second への参照を返すだけの getter の 2 つのペア (const と non) を作成できますが、はるかに読みやすくなります。例えば:

string& GetField(pair& p) { return p.first; }
int& GetValue(pair& p) { return p.second; }

どのメンバーが何を保持しているかを覚えておく必要なく、特定のペアからフィールド メンバーと値メンバーを取得できます。

これを頻繁に使用することが予想される場合は、MAKE_PAIR_GETTERS(Field, string, Value, int) などの名前と型を指定して、これらのゲッターを生成するマクロを作成することもできます。ゲッターを単純にすることで、おそらくコンパイラーがゲッターを最適化して除去できるようになるため、実行時にオーバーヘッドが追加されることはありません。マクロを使用すると、ペアをどのように使用する場合でも、これらのゲッターを簡単に作成できます。

于 2009-06-25T06:42:17.970 に答える
2

ブーストタプルを使用することもできますが、根本的な問題を実際に変更することはありません:ペア/タプルの各部分に小さな整数型で本当にアクセスしたいですか?それとも、より「リテラシーな」コードが必要ですか? 少し前に投稿したこの質問を参照してください。

ただし、boost::optionalは便利なツールであり、ペア/タプルが答えとして宣伝されているかなりの数のケースに取って代わります。

于 2009-06-25T09:41:46.627 に答える
1

Alexが述べたように、std::pair非常に便利ですが、構造を作成して同じように使用するのが混乱する場合は、std::pairコードを見てください。それほど複雑ではありません。

于 2009-06-25T05:51:01.490 に答える
1

std::map で使用されている std::pair も好きではありません。マップエントリにはキーと値のメンバーが必要です。
これを避けるために、boost::MIC も使用しました。ただし、boost::MIC にもコストがかかります。

また、 std::pair を返すと、読みにくいコードになります。

if (cntnr.insert(newEntry).second) { ... }

???

また、std::pair は、2 つの値が必要であるが、これらの値が一緒に必要な理由を考えていなかった怠惰なプログラマーによって一般的に使用されていることもわかりました。

于 2009-06-25T10:06:32.053 に答える