Как определить оператор сравнения (меньше, чем) на массиве двойников? - PullRequest
0 голосов
/ 05 декабря 2018

Я реализую кэш для сохранения вызовов функций.

Допустим, у меня есть 2 double параметров для моего вызова функции.

Это должны быть ключи некоторого кэша LRU или- чтобы сделать это проще - C ++ std::map.

Поэтому я создал шаблонный класс с массивом внутри (переменное число значений)

template <int n>
  class DoubleArray
  {
    public:   
    double array[n];
   };

При попытке использовать его какключ моего std::map, компилятор пожаловался, потому что для них требовался operator<.

.....\include\c++\7.3.1\bits\stl_function.h:386:20: note:
'const DoubleArray<2>' is not derived from 'const std::map<_Key, _Tp, _Compare,
_Alloc>'
       { return __x < __y; }
                ~~~~^~~~~

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

#include <map>

template <int n>
  class DoubleArray
  {
    public:   
    double array[n];
    bool operator<(const DoubleArray &other) const
    {      
      return (array[0] < other.array[0]) || (array[0] == other.array[0] && array[1] < other.array[1]);
    }

  };

int main()
{
   std::map<DoubleArray<2>,double> my_cache;
   DoubleArray<2> params;
   // clumsy way to initialize the array...
   params.array[0] = 12;
   params.array[1] = 2;
   // put a value in cache
   my_cache[params] = 23;
}

Обратите внимание, что оператор сравнения действительно неуклюжий.Что если у меня есть 6 параметров (это мой реальный случай).

Как создать универсальный оператор сравнения (возможно, с использованием рекурсии шаблона)?

В случае, если это проблема XY, есть либолее простой способ создания n-значной карты ключей с типами double?

(обратите внимание, что я полностью осознаю, что использование значений double в качестве ключей выглядит плохо, но моя цель - кэшировать значения навызовы функций, где параметры в точности совпадают, они не предназначены для хранения или тому подобное)

Ответы [ 4 ]

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

Не изобретайте колесо, используйте std :: array.У него уже есть перегруженный оператор <.Всегда рассматривайте возможность использования и комбинирования того, что предлагает стандартная библиотека и другие известные библиотеки, прежде чем писать собственное решение: <a href="http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#sl1--use-libraries-wherever-possible" rel="nofollow noreferrer"> Используйте библиотеки, когда это возможно .

Затем вы можете объявить свою карту следующим образом:

std::map<std::array<double, 2>, double> my_cache;
0 голосов
/ 05 декабря 2018

Вы можете обойти проблему, используя std::array.Используя объявление псевдонима , ваш код может быть упрощен до

template <std::size_t N>
using DoubleArray = std::array<double, N>;

int main()
{
   std::map<DoubleArray<2>,double> my_cache;
   my_cache[{12, 2}] = 23;
}
0 голосов
/ 05 декабря 2018

Как создать универсальный оператор сравнения (возможно, с использованием рекурсии шаблона)?

Вы можете попробовать этот метод:

#include <utility>     // std::index_sequence
#include <tuple>       // std::tie

template <int N>
struct DoubleArray
{
private:
    template <size_t ... Is>
    bool opHelper(const DoubleArray& rhs, std::index_sequence<Is...>) const
    {
        return std::tie(arr[Is]...) < std::tie(rhs.arr[Is]...);
    }

public:
    double arr[N];

    bool operator<(const DoubleArray& rhs) const
    {
        return opHelper(rhs, std::make_index_sequence<N>{});
    }
};
0 голосов
/ 05 декабря 2018

Вы ищете std::lexicographical_compare

bool operator<(const DoubleArray &other) const
{      
    return std::lexicographical_compare(array, array + n, other.array, other.array + n);
}

Кроме того, вы можете просто определить псевдоним для std::array, в котором уже определены все операторы сравнения

template<int n>
using DoubleArray = std::array<double, n>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...