Пользовательский key_comp с классом, который принимает аргумент для набора c ++ - PullRequest
0 голосов
/ 12 декабря 2018

Я пытался создать набор Vector3d s (из библиотеки Eigen).Кроме того, набор примет key_comp из пользовательского класса, который также принимает аргумент.Ниже приведен мой код

#include <set>
#include <Eigen/Core>

using namespace std;
using namespace Eigen;

class Vector3dNormCompareClass {
public:
        Vector3dNormCompareClass(const double prec) {
                _prec = prec;
        }
        bool operator ()(const Vector3d lhs, const Vector3d rhs) const;
private:
        double _prec;
};

bool Vector3dNormCompareClass::operator ()(const Vector3d lhs,
                const Vector3d rhs) const {    
        if (lhs.norm() < rhs.norm())
                return true;

        for (int i = 0; i < 3; ++i) {
                if (abs(lhs(i) - rhs(i)) > _prec)
                        return lhs(i) < rhs(i);
        }
        return false;
}

class Tan {    
    set<Vector3d,Vector3dNormCompareClass> _transList;
    public:
    void setTransList(double foo);    
};


void Tan::setTransList(double foo) {
    Vector3dNormCompareClass comp(foo);
    _transList(comp);    
}

Здесь _transList - это набор, который я хочу построить, когда объявлен класс Tan, а Vector3dNormCompareClass - это класс для key_comp, который принимаетаргумент для точности сравнения (так как мы сравниваем векторы двойников).Кроме того, в моем случае я хочу иметь возможность сбросить точность key_comp, то есть Vector3dNormCompareClass, но с текущей формой мой код, к сожалению, не компилируется.Может ли кто-нибудь помочь мне, как определить список так, чтобы он мог принять пользовательский key_comp с его аргументом (то есть double prec)?

ОБНОВЛЕНИЕ Поскольку некоторые из вас, очевидно, более обеспокоеныо математической достоверности моего key_comp, я добавил в него некоторый код: if (lhs.norm() < rhs.norm()) return true;, чтобы выполнить условие, определенное здесь , я цитирую:

Объект set используетэто выражение для определения порядка следования элементов в контейнере и эквивалентности двух ключей элементов (путем их рефлексивного сравнения: они эквивалентны, если! comp (a, b) &&! comp (b, a)).Никакие два элемента в контейнере набора не могут быть эквивалентными.

Таким образом, проверяя (a<b) & (b>a), я полагаю, что мой key_comp выполнит условие для определения эквивалентных ключей.Тем не менее, double prec здесь теперь используется для упорядочения ключей, и я хочу сделать его «гибким», то есть иметь возможность сброса, возможно, каждый раз, когда я очищаю _transList, то есть _transList.clear().Так что моя проблема все еще существует, а именно, код не компилируется с текущей формой, и я был бы признателен, если бы кто-то мог помочь мне с этой проблемой!

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

Я считаю, что вы не можете определить компаратор для ассоциативных контейнеров таким образом в случае ключей с плавающей запятой.Стандарт C ++ требует, чтобы равенство, полученное из компаратора, было транзитивным, например: equiv(a, b) && equiv(b, c) подразумевает equiv(a, c), где equiv(a, b) определяется как !comp(a, b) && !comp(b, a).

Используя клавиши с плавающей точкой и сравнивая с некоторой точностью, вы можете получить equiv(a, b) и equiv(b, c), являющиеся true (оба отличаются меньше точности), но equiv(a, c), являющиеся false (суммаразница выше точности).


Пример для скалярных ключей

Рассмотрим _prec, равное 0,1 (это высоко для примерных целей, вы можете сделатьтакой же анализ для любого значения).Тогда comp(a, b), определяемое как abs(a, b) < 0.1, будет означать, что equiv(1.10, 1.19) равно true, а также equiv(1.19, 1.28), но equiv(1.10, 1.28) будет false.

0 голосов
/ 12 декабря 2018

Вы не можете просто сбросить компаратор, так как это (вероятно) также изменит внутренний порядок.Однако вы можете сбросить набор с помощью нового компаратора (и при необходимости вставить текущие значения):

void Tan::setTransList(double foo) {
    Vector3dNormCompareClass comp(foo);
    set<Vector3d,Vector3dNormCompareClass> tmp(
        _transList.begin(), _transList.end(), // remove this line if you don't want to copy old entries
        comp); 
    _transList.swap(tmp);    
}

Редактировать: Как указал Даниэль, ваш компаратор не удовлетворяет необходимым критериям длянабор (а именно транзитивный), т. е. вы, вероятно, получите неожиданные результаты (в зависимости от порядка вставки значений).

...