Literate Coding Vs. std :: pair、ソリューション?
-
22-07-2019 - |
質問
ほとんどのプログラマーが賞賛し、Literateプログラミングの原則に従うことを試みますが、C ++では日常的に std :: pair
を使用して、膨大な一般的なタスクを行っています。しかし、 std :: pair
は、私見、リテラシープログラミングの敵です...
私のポイントは、1、2日前に書いたコードに戻ったときであり、 std :: pair
(通常はイテレーターとして)の操作を確認します&quot ; iter-> firstおよびiter-> secondの意味??? "。
std :: pair
のコードを見ると他の人も同じ疑問を抱いていると思うので、を使用するときにリテラシーを回復するための優れたソリューションを誰かが思いついたstd :: pair
?
解決
これについてはどうですか:
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" );
これ以外に、物事をより明確にする銀の弾丸は見られません。
他のヒント
std :: pair
は、「ローカル」を作成する良い方法です。本質的に匿名の列を持つ本質的に匿名の型。型と列に名前を付ける必要があるほど大きなレキシカルスペースで特定のペアを使用している場合は、代わりにプレーンな struct
を使用します。
typedef std::pair<bool, int> IsPresent_Value;
typedef std::pair<double, int> Price_Quantity;
...ポイントを取得します。
最初と2番目への参照を返すだけの2つのゲッターのペア(constとnon)を作成できますが、はるかに読みやすくなります。例えば:
string& GetField(pair& p) { return p.first; }
int& GetValue(pair& p) { return p.second; }
どのメンバーが何を保持しているかを覚えなくても、指定されたペアからフィールドメンバーと値メンバーを取得できます。
これを頻繁に使用する場合は、MAKE_PAIR_GETTERS(Field、string、Value、int)などの名前とタイプを指定して、これらのゲッターを生成するマクロを作成することもできます。ゲッターを簡単に作成すると、コンパイラーがゲッターを最適化することができるため、実行時にオーバーヘッドが追加されません。マクロを使用すると、ペアを作成する際に使用するゲッターを簡単に作成できます。
ブーストタプルを使用できますが、根本的な問題を実際に変更することはありません。本当には、小さな整数型でペア/タプルの各部分にアクセスするか、より多くの「リテラシー」コード。 この質問しばらく前に投稿しました。
ただし、 boost :: optional は、ペア/タプルが答えとして宣伝されているケースのかなりの部分を置き換える便利なツールです。
最近、 std :: pair
の代わりに boost :: tuple
を使用していることに気付きました。各メンバーに列挙子を定義できるため、各メンバーが明らかです:
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
がIDと値をより密接に結び付けているようです。
アレックスが述べたように、 std :: pair
は非常に便利ですが、混乱する場合は、構造を作成して同じように使用し、 std :: pair を見てくださいcode>コード、それほど複雑ではありません。
std :: mapで使用されているstd :: pairも好きではありません。マップエントリにはメンバーキーと値が必要です。
これを避けるためにboost :: MICを使用しました。ただし、boost :: MICにはコストもかかります。
また、std :: pairを返すと、読み取り可能なコードが少なくなります:
if (cntnr.insert(newEntry).second) { ... }
???
また、std :: pairは、2つの値を必要とするが、これらの値が一緒に必要な理由を考えていない怠zyなプログラマーによってよく使用されることもわかりました。