一意のエッジを持つ unordered_set を持つことができるように、Edge 構造体をハッシュしようとしています。私の場合、エッジの 2 つのエンドポイントの組み合わせが以前のセットで検出されなかった場合、エッジは一意であると見なされます。
私のコードは、Edge 型だけを含む unordered_set に対しては正常に動作しますが、Edge 型へのポインターに対しては動作しません。以下のやや長いコードを参照してください。どんな助けでも大歓迎です。
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <unordered_set>
struct Vector3
{
float x, y, z;
Vector3() {}
Vector3(float xx, float yy, float zz)
{
x = xx, y = yy, z = zz;
}
inline bool operator==(const Vector3& other) const
{
return x == other.x && y == other.y && z == other.z;
}
friend std::ostream& operator<<(std::ostream& stream, const Vector3& vector);
};
std::ostream& operator<<(std::ostream& stream, const Vector3& vector)
{
return stream
<< "("
<< std::setw(2) << std::setfill(' ') << vector.x << ", "
<< std::setw(2) << std::setfill(' ') << vector.y << ", "
<< std::setw(2) << std::setfill(' ') << vector.z
<< ")";
}
struct Edge
{
Vector3 EndPoints[2];
Edge() {}
Edge(Vector3 p, Vector3 q)
{
EndPoints[0] = p;
EndPoints[1] = q;
}
inline bool operator==(const Edge& other) const
{
return (EndPoints[0] == other.EndPoints[0] || EndPoints[0] == other.EndPoints[1]) &&
(EndPoints[1] == other.EndPoints[1] || EndPoints[1] == other.EndPoints[0]);
}
inline bool operator==(const Edge* other) const
{
return (EndPoints[0] == other->EndPoints[0] || EndPoints[0] == other->EndPoints[1]) &&
(EndPoints[1] == other->EndPoints[1] || EndPoints[1] == other->EndPoints[0]);
}
friend std::ostream& operator<<(std::ostream& stream, const Edge& vector);
friend std::ostream& operator<<(std::ostream& stream, const Edge* vector);
};
std::ostream& operator<<(std::ostream& stream, const Edge& edge)
{
return stream << edge.EndPoints[0] << " -- " << edge.EndPoints[1];
}
std::ostream& operator<<(std::ostream& stream, const Edge* edge)
{
return stream << edge->EndPoints[0] << " -- " << edge->EndPoints[1];
}
namespace std
{
template <>
struct hash<Edge>
{
std::size_t operator()(const Edge& edge) const
{
Vector3 p0 = edge.EndPoints[0];
Vector3 p1 = edge.EndPoints[1];
if (p1.x < p0.x) std::swap(p0.x, p1.x);
if (p1.y < p0.y) std::swap(p0.y, p1.y);
if (p1.z < p0.z) std::swap(p0.z, p1.z);
unsigned hash0 = (int(p0.x*73856093) ^ int(p0.y*19349663) ^ int(p0.z*83492791)) % 1024;
unsigned hash1 = (int(p1.x*73856093) ^ int(p1.y*19349663) ^ int(p1.z*83492791)) % 1024;
return hash0 ^ (hash1 << 3);
}
};
template <>
struct hash<Edge*>
{
std::size_t operator()(const Edge* edge) const
{
Vector3 p0 = edge->EndPoints[0];
Vector3 p1 = edge->EndPoints[1];
if (p1.x < p0.x) std::swap(p0.x, p1.x);
if (p1.y < p0.y) std::swap(p0.y, p1.y);
if (p1.z < p0.z) std::swap(p0.z, p1.z);
unsigned hash0 = (int(p0.x*73856093) ^ int(p0.y*19349663) ^ int(p0.z*83492791)) % 1024;
unsigned hash1 = (int(p1.x*73856093) ^ int(p1.y*19349663) ^ int(p1.z*83492791)) % 1024;
std::size_t key = hash0 ^ (hash1 << 3);
return key;
}
};
}
void add_edge(std::unordered_set<Edge>& table, Edge edge)
{
std::unordered_set<Edge>::const_iterator it = table.find(edge);
if (it == table.end()) table.insert(edge);
else std::cout << "Table already contains edge " << edge << std::endl;
}
void add_edge(std::unordered_set<Edge*>& table, Edge* edge)
{
std::unordered_set<Edge*>::const_iterator it = table.find(edge);
if (it == table.end()) table.insert(edge);
else std::cout << "Table already contains edge " << edge << std::endl;
}
void print_table(std::unordered_set<Edge>& table)
{
std::cout << std::endl;
std::cout << "Table has " << table.size() << " elements:" << std::endl;
for (auto it = table.begin(); it != table.end(); ++it)
std::cout << *it << std::endl;
std::cout << std::endl;
}
void print_table(std::unordered_set<Edge*>& table)
{
std::cout << std::endl;
std::cout << "Table has " << table.size() << " elements:" << std::endl;
for (auto it = table.begin(); it != table.end(); ++it)
std::cout << *(*it) << std::endl;
std::cout << std::endl;
}
int main()
{
std::unordered_set<Edge> table;
std::unordered_set<Edge*> ptable;
Edge e0(Vector3( 1.f, 0.f, 0.f), Vector3(-1.f, 0.f, 0.f));
Edge e1(Vector3(-1.f, 0.f, 0.f), Vector3( 1.f, 0.f, 0.f));
add_edge(table, e0);
add_edge(table, e1);
print_table(table);
add_edge(ptable, &e0);
add_edge(ptable, &e1);
print_table(ptable);
return 0;
}
これは出力です:
1> Table already contains edge (-1, 0, 0) -- ( 1, 0, 0)
1>
1> Table has 1 elements:
1> ( 1, 0, 0) -- (-1, 0, 0)
1>
1> Table has 2 elements:
1> (-1, 0, 0) -- ( 1, 0, 0)
1> ( 1, 0, 0) -- (-1, 0, 0)
だから私の質問は: 2 番目の要素が 2 番目のテーブルに追加されるのはなぜですか? ハッシュ関数を確認しましたが、両方のエントリに対して同じキーが返されるため、それが原因ではないようですが、他に何が考えられるかはわかりません。
編集:
が呼び出されていないことがわかりましたが、そのinline bool operator==(const Edge* other) const
理由はわかりません。