Я хотел бы использовать оператор трехстороннего сравнения по умолчанию в рекурсивной структуре данных, например:
struct MyStruct {
int i;
std::vector<MyStruct> v;
std::partial_ordering operator<=>(const MyStruct &a) const = default;
};
// Fails: can't infer comparison result type
static_assert(std::same_as<std::compare_three_way_result_t<MyStruct>,
std::partial_ordering>);
К сожалению, похоже, существует циклическая зависимость, поскольку оператор <=>
по умолчанию зависит от категорий сравнения целочисленного сравнения и std::vector, тогда как категория векторного сравнения зависит от категории сравнения, если это value_type
, а именно MyStruct
. Тот факт, что я явно объявил тип сравнения std::partial_ordering
, похоже, не помогает, хотя и должен. В частности, это работает, если я реализую функцию вручную:
struct MyStruct {
int i;
std::vector<MyStruct> v;
std::partial_ordering operator<=>(const MyStruct &other) const {
if (auto r = i <=> other.i; r != 0)
return r;
return v <=> other.v;
}
};
// OK
static_assert(std::same_as<std::compare_three_way_result_t<MyStruct>,
std::partial_ordering>);
Мои вопросы:
Есть ли способ обойти эту проблему? Спецификация запрещает перегрузку std::compare_three_way_result, но есть ли другой способ повлиять на vector
или std::lexicographical_compare_three_way
?
Есть ли способ, используя концепции или предложения, обнаружить неполный тип? В качестве альтернативы я мог бы создать свой собственный векторный класс-контейнер, который по умолчанию использует значение std::partial_ordering
, когда тип неполный.
@PepijnKramer Я никогда не слышал, чтобы условный оператор назывался «трехсторонним оператором» (да, тройной, но это три части, а не трехсторонний), официальное название «оператора космического корабля» - трехсторонний оператор сравнения
@AlanBirtles Упс, мне правда не следует отвечать утром до первого кофе. Мне плохо ;)
Если вы действительно укажете std::partial_ordering
самостоятельно (т. е. без auto
), то вы можете определить оператор сравнения вне класса как встроенную функцию. На этом урок завершен.
struct MyStruct {
int i;
std::vector<MyStruct> v;
std::partial_ordering operator<=>(const MyStruct &) const;
};
inline std::partial_ordering MyStruct::operator<=>(const MyStruct &) const = default;
Я не уверен, что ваш исходный код действительно плохо сформирован, если подумать (это означает, что = default;
в спецификации члена уже является полным контекстом класса), если только нет стандартного дефекта, который я пропустил.
Что ж, g++ принимает ваше предложение, но clang++ 18.1 отклоняет его как с libc++, так и с libstdc++.
@ user3188445 — я повозился с этим и сильно подозреваю, что это ошибка интерфейса clang, сосредоточенная вокруг операций сравнения по умолчанию (таких сообщается немало github.com/llvm/llvm-project/… ). Например, вместо этого я немного упростил пример до значения по умолчанию operator==
и получил этот сбой компилятора в Clang 17 (который также отклонил мое предложение при проверке). Я думаю, что ваше явное определение - лучший обходной путь.
Хорошо, спасибо за расследование. Тогда я отмечу ваш ответ как правильный.
Трехсторонний оператор —
auto x = false ? 1 : 2
. То, на что вы ссылаетесь, (неофициально) называетсяspaceship operator