Строгий слабый порядок значений указателя - PullRequest
0 голосов
/ 15 января 2019

Рассмотрим следующую структуру:

struct Foo {
  const Bar* x;
  const Bar* y;

  Foo(const Bar* _x, const Bar* _y = nullptr) : x(_x), y(_y) { assert(x); }
}

Как мы определяем строгий слабый порядок по x и y, чтобы объект можно было использовать в std :: set? Обратите внимание, что у может быть нулевым указателем. Как упомянуто в При использовании std :: less с nullptr поведение std :: less для нулевых указателей undefined не указано. Будет ли достаточно следующего решения?

bool operator<(const Foo& rhs) const {
  uintptr_t numX = reinterpret_cast<uintptr_t>(x);
  uintptr_t numY = reinterpret_cast<uintptr_t>(y);

  uintptr_t numRhsX = reinterpret_cast<uintptr_t>(rhs.x);
  uintptr_t numRhsY = reinterpret_cast<uintptr_t>(rhs.y);

  return std::tie(numX, numY) < std::tie(numRhsX, numRhsY);
}

РЕДАКТИРОВАТЬ: Если нет, то как правильно (например, как объединить std :: less с std :: tie)?

1 Ответ

0 голосов
/ 15 января 2019

Использование std::less<Bar*> достаточно (но использование operator< не достаточно). Специализация указателя std::less (как принятый ответ на "Использование std :: less with nullptr" указывает на) гарантирует общее упорядочение . Сравнение с nullptr является неопределенным , что означает, что стандарт не налагает конкретное упорядочение, но std::less все равно должно производить a общее упорядочение (и для данный указатель p, p < nullptr обязательно выдает одно и то же значение каждый раз).

Поскольку общий порядок сильнее слабого, в вашем случае достаточно использовать std::less.

РЕДАКТИРОВАТЬ: Если нет, то как правильно (например, как объединить std :: less с std :: tie)?

Чистого пути, к сожалению, нет. Поскольку std::tie возвращает std::tuple, а сравнение для кортежей определяется в терминах operator< по их значениям (а не std::less), вы не можете использовать std::tie здесь. Чтобы использовать std::less, вам придется сделать это вручную:

bool operator<(const Foo& rhs) const {
  if (std::less<>{}(x, rhs.x))
    return true;
  if (std::less<>{}(rhs.x, x))
    return false;
  return std::less<>{}(y, rhs.y);
}

Кроме того, ваша текущая реализация (реинтерпретация указателей как целых чисел) также производит полное упорядочение (очевидно, поскольку вы сравниваете целые числа), но вместо неопределенного поведения у вас будет Поведение, определяемое реализацией (из reinterpret_cast).

...