Как std :: strong_ordering работает только с нуля? - PullRequest
3 голосов
/ 25 февраля 2020

Я просто исследую трехстороннее сравнение оператор <=>. Я вижу, что он возвращает std::strong_ordering. Однако я не понимаю, как компилятор ограничивает только 0 в операторах сравнения (so<0, но не so<1)

#include<compare>
int main()
{
  std::strong_ordering so = 55 <=> 10;

  so < 0; // Fine
  so < 1; // Fails
}

Аналогично, so>20 также не будет работать. Следующее также не будет работать:

constexpr int Zero = 0;
so == Zero; // Error
so == 0; // Fine

EDIT - Интересное наблюдение (на компиляторе MSV C). Действителен:

so < nullptr

1 Ответ

4 голосов
/ 25 февраля 2020

Использование всего, кроме литерала 0 для сравнения с std::strong_ordering - явное неопределенное поведение, см. [cmp.categories.pre] / 3 черновика C ++ 20.

Компилятор / стандартная библиотека решает, как или нужно ли это применять / диагностировать.

Один из способов достижения диагноза c для UB без какого-либо магического компилятора c - использовать std::nullptr_t в качестве аргумента для перегруженного оператора сравнения std::strong_ordering (который имеет неопределенный тип в соответствии со стандартом). Любой интеграл с нулевым литералом может быть неявно преобразован в std::nullptr_t, но литералы с другими значениями или константными выражениями, которые не являются литералами, не могут. См. [conv.ptr] / 1 .

Это также упоминается в черновике как возможность.

В Libc ++ вместо этого используется указатель на некоторый скрытый класс. смотрите здесь .

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

Однако ни одна из этих реализаций не диагностирует все аргументы, которые приводят к UB согласно стандарту. В частности, все они также принимают nullptr в качестве аргумента без диагноза c: https://godbolt.org/z/esnvqR

Я полагаю, что для полной диагностики всех случаев потребуется некоторый магический компилятор c.

...