Подтвердить что ты не робот

Грамотное кодирование Vs. std:: pair, решения?

Как и большинство программистов, я восхищаюсь и стараюсь следовать принципам грамотного программирования, но на С++ я обычно использую std::pair для общих задач. Но std::pair есть, ИМХО, гнусный враг грамотного программирования...

Моя точка зрения - когда я возвращаюсь к коду, который я написал день или два назад, и я вижу манипуляции с std::pair (обычно как итератор), я задаюсь вопросом: "Что сделал iter- > first and iter → второе среднее значение".

Я предполагаю, что у других есть те же сомнения, когда они смотрят на их код std::pair, поэтому мне было интересно, есть ли у кого-нибудь подходящие решения для восстановления грамотности при использовании std::pair?

4b9b3361

Ответ 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 значения, но не думал, почему эти значения необходимы вместе.