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
,没有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);
}
我会做类似的事情
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 指针进行比较,否则会出现不一致的行为。
我想在 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
,没有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);
}
我会做类似的事情
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 指针进行比较,否则会出现不一致的行为。