我想在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;
}
}
};
答案 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
,没有声明t
或u
),然后看它试图实例化
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);
}
无论采用哪种方法,都需要注意不要通过基类指针进行比较,否则行为会不一致。