【发布时间】:2019-01-16 18:11:12
【问题描述】:
我想通过两个自定义类的成员返回值对 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 test
输出:
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
【问题讨论】:
-
很确定变体的比较重载会比较两个变体中的 which 替代方案,然后仅当两个变体具有相同的基础类型时才直接比较它们. IE。它首先比较
index()。 -
FWIW,
std::visit可以同时访问多个变种,所以第一个sn-p可以是std::visit([](auto const& lhs, auto const& rhs) { return lhs.area() < rhs.area(); }, a, b) -
@SamVarshavchik 啊,我明白了。我想这解决了,我必须使用 std::visit