簡體   English   中英

排序矢量 <variant<…> &gt;通過運算符無法正常工作

[英]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 :: 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;
}

有人能指出我正確的方向嗎? 我懷疑問題在於操作員<不適用於不同類型。

編譯命令: $ 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

這個:

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排序時,您不會按區域排序。 你有效地按元組排序(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::variantoperator<工作原理。 它首先比較索引,並且只有當索引相等時,它才會比較值: https//en.cppreference.com/w/cpp/utility/variant/operator_cmp 對於不相等的索引,如果第一個變量的索引小於第二個變量,則返回true

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM