C++ 无序对类型

C++ Unordered Pair Type

我想在 C++ 中创建一个无序对类型,即 unordered_set 保证恰好有两个元素。这是我想出的,但问题是如果我使用这种方法,还有很多我必须覆盖的东西——每个比较运算符,等等。有没有更简单的方法?

class unordered_pair : public std::pair<t, u>
{
public:
    unordered_pair(t x, u y) : std::pair<t, u>(x,y) {};
    bool operator ==(const unordered_pair<t,u>& rhs)
    {
        if ((this->first < this->second) ^ (rhs.first < rhs.second))
        {
            return this->second == rhs.first && this->first == rhs.second;
        }
        else
        {
            return this->first == rhs.first && this->second == rhs.second;
        }
    }
};

让我们在这个模板中填充一些类型(你省略了template,没有tu的声明),看看它试图实例化什么

unordered_pair<int, std::string> pair, pair2;

bool operator ==(const unordered_pair<t,u>& rhs)
{
    if ((this->first < this->second) ^ (rhs.first < rhs.second))

这是 bool operator <(int, std::string)bool operator <(std::string, int)。这些不存在。

    {
        return this->second == rhs.first && this->first == rhs.second;
    }

这是 bool operator ==(int, std::string)bool operator ==(std::string, int)。这些也不存在。

    else
    {
        return this->first == rhs.first && this->second == rhs.second;
    }
}

您需要 一个 模板类型参数。尝试这样的事情

class bad_unordered_pair : public std::exception
{
    const char * what() const { return "unordered_pair must have exactly two distinct values"; }
}

template <typename T>
std::pair<T, T> make_unordered_pair(T first, T second)
{
    std::hash<T> hash;
    if (first == second) throw bad_unordered_pair{};
    if (hash(first) < hash(second)) return unordered_pair(first, second);
    return unordered_pair(second, first);
}

我会做类似的事情

struct unordered_pair : std::pair<t, u>
{
    bool swapped;

    unordered_pair(t x, u y) : 
        std::pair<t, u>(x,y),
        swapped(false);
    {
        sort();
    }

    void sort() {
        swapped = first > second;
        if (swapped)
            std::swap(first, second);
    }

    std::pair<t, u> getOrig() {
        if (swapped)
            return std::pair<t,u>(second, first);
        return std::pair<t, u>(first, second);
    }
}

那么每次改变 first 或 second 时,你只需调用 sort() ;并且所有的比较运算符都是从std::pair免费获得的!

动机是如果你不关心比较的顺序,那么你大部分时间都不会关心顺序;这意味着大多数时候,您不需要获得原始物品。

编辑:您在评论中声明我们可以假设 t==u ...在这种情况下,我建议去掉 t 或 u - 并使其仅 std::pair<t, t>

旁白:我假设你的意思是

template<typename t>
class unordered_pair : public std::pair<t, t>

因为如果成员应该可以互换,那么成员属于不同类型是没有意义的。


您可以编写一个简单的 sorted() 方法,以简化这些重载的编写:

private:
    std::tuple<t const&, t const&> ordered() const noexcept
    {
        return (this->first < this->second)
            ? std::tie(this->first, this->second)
            : std::tie(this->second, this->first);
    }
};

然后使用它实现 ==<

bool operator ==(const unordered_pair<t>& rhs) const noexcept
{
    return ordered() == rhs.ordered();
}
bool operator <(const unordered_pair<t>& rhs) const noexcept
{
    return ordered() < rhs.ordered();
}

和其他运营商而言:

bool operator !=(const unordered_pair<t>& rhs) const noexcept
{
    return !(*this == rhs);
}

bool operator >(const unordered_pair<t>& rhs) const noexcept
{
    return rhs < *this;
}

bool operator <=(const unordered_pair<t>& rhs) const noexcept
{
    return !(rhs < *this);
}

bool operator >=(const unordered_pair<t>& rhs) const noexcept
{
    return !(*this < rhs);
}

或者,如果您有 C++20,则改为实现 <=>

template<typename T>
class unordered_pair : public std::pair<T, T>
{
public:
    unordered_pair(T x, T y)
        : std::pair<T, T>(x,y)
    {}

    std::strong_ordering operator<=>(const unordered_pair<T>& other)
    {
        return ordered() <=> other.ordered();
    }

private:
    std::tuple<T const&, T const&> ordered() const noexcept
    {
        return (this->first < this->second)
            ? std::tie(this->first, this->second)
            : std::tie(this->second, this->first);
    }
};

甚至把帮手吸进算子里:

std::strong_ordering operator<=>(const unordered_pair<T>& other)
{
    auto ordered = [](unordered_pair<T> const& t) {
        return (t.first < t.second)
        ? std::tie(t.first, t.second)
        : std::tie(t.second, t.first);
    };

    return ordered(*this) <=> ordered(other);
}

无论采用哪种方法,都需要注意不要通过 base-class 指针进行比较,否则会出现不一致的行为。