Грамотное кодирование Vs. std:: pair, решения?
Как и большинство программистов, я восхищаюсь и стараюсь следовать принципам грамотного программирования, но на С++ я обычно использую std::pair
для общих задач. Но std::pair
есть, ИМХО, гнусный враг грамотного программирования...
Моя точка зрения - когда я возвращаюсь к коду, который я написал день или два назад, и я вижу манипуляции с std::pair
(обычно как итератор), я задаюсь вопросом: "Что сделал iter- > first and iter → второе среднее значение".
Я предполагаю, что у других есть те же сомнения, когда они смотрят на их код std::pair
, поэтому мне было интересно, есть ли у кого-нибудь подходящие решения для восстановления грамотности при использовании std::pair
?
Ответы
Ответ 1
Как насчет этого:
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" );
Кроме этого, я не вижу ни одной серебряной пули, которая сделает вещи намного яснее.
Ответ 2
std::pair
- хороший способ сделать "локальный" и по существу анонимный тип с по существу анонимными столбцами; если вы используете определенную пару по столь большому лексическому пространству, которое вам нужно назвать типом и столбцами, вместо этого я бы использовал простой struct
.
Ответ 3
typedef std::pair<bool, int> IsPresent_Value;
typedef std::pair<double, int> Price_Quantity;
... вы поняли смысл.
Ответ 4
Вы можете создать две пары геттеров (const и non), которые будут просто возвращать ссылку на первую и вторую, но будут более читаемыми. Например:
string& GetField(pair& p) { return p.first; }
int& GetValue(pair& p) { return p.second; }
Позволяет вам получать поля и значения элементов из заданной пары, не задумываясь о том, какой элемент имеет значение.
Если вы планируете использовать это много, вы также можете создать макрос, который будет генерировать эти геттеры для вас, учитывая имена и типы: MAKE_PAIR_GETTERS (поле, строка, значение, int) или так далее. Создание геттеров прямолинейно, вероятно, позволит компилятору оптимизировать их, поэтому они не добавят накладных расходов во время выполнения; и использование макроса сделает его легким для создания этих геттеров для любого использования, которое вы используете для пар.
Ответ 5
Недавно я обнаружил, что использовал 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));
}
BTW, комментарии приветствуются, если есть скрытые затраты на использование этого подхода.
EDIT: удалить имена из глобальной области.
Просто быстрый комментарий относительно глобального пространства имен. В общем, я бы использовал:
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
связывает личность и значение ближе друг к другу.
Ответ 6
Вы можете использовать форсированные кортежи, но они не меняют основной проблемы: действительно ли вы хотите получить доступ к каждой части пары/кортежа с помощью небольшого интегрального типа или вам нужен более "грамотный" код. См. этот вопрос Я опубликовал некоторое время назад.
Однако boost:: optional - полезный инструмент, который я нашел, заменяет довольно много случаев, когда пары/кортежи как ответ.
Ответ 7
Как сказал Алекс, std::pair
очень удобен, но когда он запутывается, создайте структуру и используйте ее таким же образом, посмотрите код std::pair
, это не так сложно.
Ответ 8
Мне не нравится std:: pair, как используется в std:: map, либо записи карты должны иметь ключ и значение участников.
Я даже использовал boost:: MIC, чтобы избежать этого. Тем не менее, boost:: MIC также имеет стоимость.
Кроме того, при возврате std:: pair получается менее читаемый код:
if (cntnr.insert(newEntry).second) { ... }
???
Я также обнаружил, что std:: pair обычно используется ленивыми программистами, которым нужны 2 значения, но не думал, почему эти значения необходимы вместе.