Определение == и ‹ для структур с большим количеством элементов данных

Как обобщить определение ‹, если структура имеет произвольное количество элементов данных (‹ следует определять с использованием порядка, в котором перечислены элементы данных)? Простой пример с тремя элементами данных:

struct nData {
    int a;
    double b;
    CustomClass c;   // with == and < defined for CustomClass
    bool operator == (const nData& other) {return (a == other.a) && (b == other.b) && (c == other.c);}
    bool operator < (const nData& other) {
        if (  (a < other.a)  ||  ((a == other.a) && (b < other.b))  ||
                ((a == other.a) && (b == other.b) && (c < other.c))  )
            return true;
        return false;
    }
};

Как-то использовать вариативные шаблоны и рекурсию?


person prestokeys    schedule 17.02.2014    source источник
comment
Однако вы хотите, чтобы данные были упорядочены.   -  person SLaks    schedule 17.02.2014


Ответы (2)


Вы можете использовать std::tie для создания кортежа ссылок на члены класса и использовать операторы лексикографического сравнения, определенные для кортежей:

bool operator < (const nData& other) const {  // better make it const
    return std::tie(a,b,c) < std::tie(other.a, other.b, other.c);
}
person Mike Seymour    schedule 17.02.2014
comment
И я полагаю, если вам нужна сортировка по убыванию для некоторых переменных, используйте tie(a, other.b, c) < tie(other.a, b, other.c) ? - person Ben Voigt; 17.02.2014
comment
Можно обратиться к stackoverflow.com/questions/6218812/ - person user2672165; 17.02.2014
comment
Имеет ли смысл добавлять оператор неявного преобразования к кортежу ссылок, чтобы все эти операторы реализовывались косвенно через кортеж? Или есть потенциальный риск при этом? (То же самое обсуждение возможности преобразования int-оберток в int, чтобы мы могли выполнять вычисления с этими обертками, приводит к выводу, что вам не следует этого делать.) - person leemes; 17.02.2014
comment
@Ben: Или tie(a, -b, c) < tie(other.a, -other.b, other.c) для типов, где - дешево или удобочитаемость важнее производительности, я думаю :) - person Niklas B.; 17.02.2014
comment
Это определенно правильный путь, если вы можете рассчитывать на то, что он будет доступен. Однако это это функция C++11, поэтому, если вы застряли со старым компилятором (как и большинство людей)... - person James Kanze; 17.02.2014
comment
@BenVoigt: Вы могли бы; хотя я бы назвал это как-то иначе, если бы это не представляло меньше, чем отношение. - person Mike Seymour; 17.02.2014
comment
@James Kanze Если у вас нет С++ 11, вы все равно можете легко использовать вместо него boost::tie. - person Mark B; 17.02.2014
comment
@MarkB А ты можешь? Не втягивая в себя множество других вещей, которые вам не нужны? (Я не знаю ситуацию с boost::tie, но знаю, что это часто проблема с Boost.) - person James Kanze; 17.02.2014

Эта структура легко масштабируется и позволяет использовать произвольные функции сравнения (например, strcmp).

if (a != other.a) return a < other.a;
if (b != other.b) return b < other.b;
if (c != other.c) return c < other.c;
return false;
person Ben Voigt    schedule 17.02.2014
comment
Приведенные выше решения подходят, скажем, для 20 членов данных. Большое Вам спасибо. Но что, если есть сотни элементов данных? например int а1, а2, а3, ..., а1000; Есть ли метод рекурсии, чтобы справиться с этим? - person prestokeys; 17.02.2014
comment
Изменить, если члены данных были int a1, a2, a3, ..., a1000; тогда std::vector‹int› будет членом данных для хранения всего этого (и затем использовать std::lexicographical_compare). А что, если элементы данных были int a1, a2, ..., a500; двойной b1, b2, ...., b300; и т.д... ? - person prestokeys; 17.02.2014
comment
@prestokeys: Ваш дизайн сломан. Если у вас так много переменных-членов, организуйте их в какой-то контейнер (массив, карту и т. д.). - person Ben Voigt; 17.02.2014