Реализация операторов сравнения через 'tuple' и 'tie', хорошая идея? - PullRequest
93 голосов
/ 02 июня 2011

(Примечание: tuple и tie можно взять из Boost или C ++ 11.)
Когда я пишу небольшие структуры только с двумя элементами, я иногда склоняюсь к выбору std::pair, так как все важные вещи для этого типа данных уже сделаны, например operator< для строгого-слабого упорядочения.
Недостатками являются довольно бесполезные имена переменных. Даже если бы я сам создал это typedef, через 2 дня я не вспомню, что именно было first и что именно second, особенно если они оба одного типа. Это становится еще хуже для более чем двух членов, так как вложение pair в значительной степени отстой.
Другой вариант для этого - tuple, либо из Boost, либо из C ++ 11, но на самом деле это не выглядит лучше и понятнее. Поэтому я сам возвращаюсь к написанию структур, включая все необходимые операторы сравнения.
Так как особенно operator< может быть довольно громоздким, я думал обойти весь этот беспорядок, просто полагаясь на операции, определенные для tuple:

Пример operator<, например для строго-слабых заказов:

bool operator<(MyStruct const& lhs, MyStruct const& rhs){
  return std::tie(lhs.one_member, lhs.another, lhs.yet_more) <
         std::tie(rhs.one_member, rhs.another, rhs.yet_more);
}

(tie делает tuple из T& ссылок из переданных аргументов.)


Редактировать : Предложение @DeadMG о частном наследовании от tuple неплохое, но у него есть некоторые недостатки:

  • Если операторы автономные (возможно, друзья), мне нужно наследовать публично
  • С помощью кастинга мои функции / операторы (особенно operator=) могут быть легко обойдены
  • С помощью решения tie я могу опустить некоторых членов, если они не имеют значения для заказа

Есть ли какие-либо недостатки в этой реализации, которые мне нужно рассмотреть?

Ответы [ 4 ]

57 голосов
/ 02 июня 2011

Это, безусловно, облегчит написание правильного оператора, чем выполнение его самостоятельно.Я бы сказал, что рассмотрим только другой подход, если профилирование показывает, что операция сравнения является трудоемкой частью вашего приложения.В противном случае простота поддержания этого должна перевесить любые возможные проблемы с производительностью.

5 голосов
/ 10 мая 2013

Я столкнулся с этой же проблемой, и мое решение использует шаблоны с ++ 11 variadic.Вот код:

Часть .h:

/***
 * Generic lexicographical less than comparator written with variadic templates
 * Usage:
 *   pass a list of arguments with the same type pair-wise, for intance
 *   lexiLessthan(3, 4, true, false, "hello", "world");
 */
bool lexiLessthan();

template<typename T, typename... Args>
bool lexiLessthan(const T &first, const T &second, Args... rest)
{
  if (first != second)
  {
    return first < second;
  }
  else
  {
    return lexiLessthan(rest...);
  }
}

И .cpp для базового случая без аргументов:

bool lexiLessthan()
{
  return false;
}

Теперь ваш пример становится следующим:

return lexiLessthan(
    lhs.one_member, rhs.one_member, 
    lhs.another, rhs.another, 
    lhs.yet_more, rhs.yet_more
);
3 голосов
/ 02 июня 2011

По-моему, вы все еще не решаете ту же проблему, что решает std::tuple, а именно: вам нужно знать как количество, так и имя каждой переменной-члена, вы дублируете ее дважды в функции. Вы можете выбрать private наследование.

struct somestruct : private std::tuple<...> {
    T& GetSomeVariable() { ... }
    // etc
};

Этот подход представляет собой немного немного больше беспорядка для начала, но вы поддерживаете только переменные и имена в одном месте, а не в каждом месте для каждого оператора, который вы хотите перегрузить.

1 голос
/ 02 июня 2011

Если вы планируете использовать более одной перегрузки оператора или несколько методов из кортежа, я бы рекомендовал сделать кортеж членом класса или наследовать от кортежа.В противном случае то, что вы делаете, - это гораздо больше работы.При выборе между этими двумя вопросами важно ответить на следующий вопрос: хотите ли вы, чтобы ваш класс был кортежем?Если нет, я бы порекомендовал содержать кортеж и ограничить интерфейс с помощью делегирования.

Вы можете создавать средства доступа для «переименования» членов кортежа.

...