C ++无序对类型

时间:2018-06-25 13:39:56

标签: c++ std-pair

我想在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;
        }
    }
};

3 个答案:

答案 0 :(得分:3)

我会做类似的事情

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);
    }
}

然后,您每次第一次或第二次更改时都只需调用sort();并且所有比较运算符都是从std :: pair免费获得的!

这样做的动机是,如果您不关心比较的顺序,那么大多数时候您就不会在意顺序。在大多数情况下,这意味着您无需获取原始商品。

编辑:您在评论中指出,我们可以假设t == u ...在这种情况下,我建议删除t或u-使其变为std::pair<t, t>

答案 1 :(得分:2)

让我们在此模板中填写一些类型(您省略了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);
}

答案 2 :(得分:1)

放在一边:我假设您的意思是

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);
}

无论采用哪种方法,都需要注意不要通过基类指针进行比较,否则行为会不一致。

相关问题