Это:
std::sort(std::begin(shapes), std::end(shapes));
использует сравнение по умолчанию sort
, которое operator<
.operator<
on std::variant
- это , определяемое как при сравнении по индексам сначала , а затем, если оба варианта содержат одну и ту же альтернативу, сравниваются базовые значения.
Другими словами:
using V = std::variant<char, int>;
V v1(static_cast<char>(42)); // holds a char
V v2(15); // holds an int
v1 < v2; // this is true, because 'char' comes before 'int'
Поэтому, когда вы сортируете свои variant
s, вы не сортируете по областям.Вы эффективно сортируете по кортежу (index, area)
.Который мы могли бы выписать долгий путь:
std::sort(std::begin(shapes), std::end(shapes),
[](auto const& lhs, auto const& rhs)
{
auto tied = [](auto const& x) {
return std::make_tuple(
// the index
x.index(),
// the area
std::visit([](auto const& e){ return e.area(); }, x)
);
};
return tied(lhs) < tied(rhs);
});
Это дает тот же порядок, что и ваш оригинальный пример.И затем, если вы удалите x.index()
часть кортежа, вы получите нужный порядок.
Но короче просто использовать многократное посещение:
std::sort(std::begin(shapes), std::end(shapes),
[](auto const& lhs, auto const& rhs)
{
std::visit([](auto const& x, auto const& y){
return x.area() < y.area();
}, lhs, rhs);
});
, которое будетеще короче в C ++ 20 с диапазонами и проекциями:
std::ranges::sort(shapes, std::less(), [](auto const& x){
return std::visit([](auto const& e){ return e.area(); }, x);
});