排序向量<变体<...>>无法通过运算符正常工作<
sorting vector<variant<...>> does not work correctly via operator<
我想按成员返回值对类型为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::variant 运算符<对它们各自的值进行操作,我认为提供模板化比较运算符看起来会更好。但是为什么它不起作用?>
法典:
#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]nn";
// 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;
}
有人能为我指出正确的方向吗?我怀疑问题出在操作员身上<</em>而不是使用不同类型的操作。
编译命令: $ g++8.2 -std=c++17 test.cpp -o test
输出:
12.5664
4
3.14159
9
[SORT]
4
9
3.14159
12.5664
奇怪的是,我在使用 godbolts 编译资源管理器和 g++8.2 时遇到了编译错误,但在使用 g++ 主干时却没有。请参阅:https://gcc.godbolt.org/z/tKJa4t
这个:
std::sort(std::begin(shapes), std::end(shapes));
使用默认的sort
比较,即 operator<
。 std::variant
operator<
定义为首先比较指数,然后,如果两个变体具有相同的替代方案,则比较基础值。
换句话说:
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
进行排序时,您不是按区域排序。您实际上是按元组(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);
});
你误解了std::variant
的operator<
是如何工作的。它首先比较索引,只有当索引相等时,它才会比较值:https://en.cppreference.com/w/cpp/utility/variant/operator_cmp。对于不相等的索引,如果第一个变体上的索引小于第二个变体上的索引,则返回true
。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中