我想通过其成员返回值对两个自定义类对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);
});
Run Code Online (Sandbox Code Playgroud)
似乎确实有用,但它非常难看.由于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;
}
Run Code Online (Sandbox Code Playgroud)
有人能指出我正确的方向吗?我怀疑问题在于操作员<不适用于不同类型.
编译命令: $ g ++ 8.2 -std = c ++ 17 test.cpp -o test
输出:
12.5664
4
3.14159
9
[SORT]
4
9
3.14159
12.5664
Run Code Online (Sandbox Code Playgroud)
奇怪的是,在使用godbolts compile explorer和g ++ 8.2时遇到编译错误,但在使用g ++ trunk时却没有.请参阅:https://gcc.godbolt.org/z/tKJa4t
这个:
std::sort(std::begin(shapes), std::end(shapes));
Run Code Online (Sandbox Code Playgroud)
使用默认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'
Run Code Online (Sandbox Code Playgroud)
因此,当您对自己进行排序时variant,您不会按区域排序.你有效地按元组排序(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);
});
Run Code Online (Sandbox Code Playgroud)
这提供了与原始示例相同的顺序.然后,如果删除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);
});
Run Code Online (Sandbox Code Playgroud)
在使用范围和预测的C++ 20中,这将变得更短:
std::ranges::sort(shapes, std::less(), [](auto const& x){
return std::visit([](auto const& e){ return e.area(); }, x);
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
108 次 |
| 最近记录: |