gpt4 book ai didi

c++ - 排序 vector> 不能通过 operator< 正常工作

转载 作者:搜寻专家 更新时间:2023-10-30 23:51:40 26 4
gpt4 key购买 nike

我想按成员返回值对具有两个自定义类的 std::variant 类型的 std::vector 进行排序。请参阅下面的代码。

现在,使用

std::sort(std::begin(shapes), std::end(shapes), [](auto const& a, auto const& b){
return std::visit([](auto const& s) { return s.area(); }, a)
< std::visit([](auto const& s) { return s.area(); }, b);
});

似乎确实有效,但是非常难看。由于 std::variants operator< 对它们各自的值进行操作,我认为提供模板化比较运算符会更好看。但为什么它不起作用?

代码:

#include <algorithm>
#include <iostream>
#include <variant>
#include <vector>

constexpr double pi = 3.141592865;

struct Square {
double d{};
double area() const { return d * d; }
};

struct Circle {
double r{};
double area() const { return pi * r * r; }
};

// comparison operator for using std::sort(begin, end);
template <class S, class T>
double operator<(S const& a, T const& b) {
return a.area() < b.area();
}

int main (int, char**)
{
std::vector<std::variant<Square, Circle>> shapes;

shapes.push_back(Circle{2});
shapes.push_back(Square{2});
shapes.push_back(Circle{1});
shapes.push_back(Square{3});

for (auto const& e: shapes)
{ std::cout << std::visit([](auto const& x) { return x.area(); }, e) << "\n"; }

std::cout << "\n[SORT]\n\n";
// Does not work
std::sort(std::begin(shapes), std::end(shapes));

/* works
std::sort(std::begin(shapes), std::end(shapes), [](auto const& a, auto const& b){
return std::visit([](auto const& s) { return s.area(); }, a)
< std::visit([](auto const& s) { return s.area(); }, b);
});
*/

for (auto const& e: shapes)
{ std::cout << std::visit([](auto const& x) { return x.area(); }, e) << "\n"; }

return 0;
}

谁能给我指出正确的方向?我怀疑问题在于 operator< 无法处理不同的类型。

编译命令: $ g++8.2 -std=c++17 test.cpp -o 测试

输出:

12.5664
4
3.14159
9

[SORT]

4
9
3.14159
12.5664

奇怪的是,我在使用 godbolts compile explorer 和 g++8.2 时遇到了编译错误,但是在使用 g++ trunk 时却没有。请参阅:https://gcc.godbolt.org/z/tKJa4t

最佳答案

这个:

std::sort(std::begin(shapes), std::end(shapes));

使用默认的sort比较,即operator< . operator<std::variantdefined as 首先比较索引,然后,如果两个变体具有相同的选择,则比较基础值。

换句话说:

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);
});

关于c++ - 排序 vector<variant<...>> 不能通过 operator< 正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54222962/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com