【发布时间】:2014-02-02 16:04:11
【问题描述】:
不详细说明我为什么要做我正在做的事情,让我描述一下这个问题。
我使用 std::set 来存储名为 VertexTypePos3Normal 的结构的唯一对象。
结构体定义如下:
struct VertexTypePos3Normal {
// ctor, dtor ..
friend bool operator==(const VertexTypePos3Normal& v1, const VertexTypePos3Normal& v2);
friend bool operator<(const VertexTypePos3Normal& v1, const VertexTypePos3Normal& v2);
glm::vec3 pos;
glm::vec3 normal;
};
bool operator<(const VertexTypePos3Normal& v1, const VertexTypePos3Normal& v2) {
return (v1.pos.x < v2.pos.x) && (v1.pos.y < v2.pos.y) && (v1.pos.z < v2.pos.z) && (v1.normal.x < v2.normal.x) && (v1.normal.y < v2.normal.y) && (v1.normal.z < v2.normal.z);
}
// operator == ommited
默认情况下 std::set 使用 std::less 作为比较函数。
所以我首先将我的集合声明为std::set<VertexTypePos3Normal> set;
插入集合的元素存储在不包含唯一值的 std::vector 中(循环遍历向量)。
使用 std::less 调用了我的操作符
下面是插入集合的方法:
void createUniqueVertices(const std::vector<const VertexTypePos3Normal>& verticesIn,
std::vector<const VertexTypePos3Normal>& verticesOut,
std::vector<unsigned short>& indicesOut)
{
//std::map<VertexTypePos3Normal, int, std::equal_to<VertexTypePos3Normal> > map;
std::set<const VertexTypePos3Normal, std::equal_to<const VertexTypePos3Normal> > set;
int indexCounter = 0;
for (auto c_it = verticesIn.cbegin(); c_it != verticesIn.cend(); ++c_it) {
//bool newlyAdded = map.insert(std::pair<VertexTypePos3Normal, int>(*c_it, indexCounter)).second;
bool newlyAdded = set.insert(*c_it).second;
//if (newlyAdded) {
//verticesOut.push_back(*c_it);
//map.insert(std::pair<VertexTypePos3Normal, int>(*c_it, indexCounter));
//++indexCounter;
//}
//indicesOut.push_back(map[*c_it]);
}
}
所以我正要尝试使用 std::equal_to 而不是 std::less 并写了 operator==。 现在奇怪的事情开始了:
虽然我不再调用 std::less,因此也不再调用 operator
所以实际上我有两个问题:
1.) 为什么我的操作符
2.) operator
编辑:感谢所有信息。看起来我完全误解了严格的弱排序。使用 std::tie 照顾它解决了我的问题。这是更新的代码:
void createUniqueVertices(const std::vector<const VertexTypePos3Normal>& verticesIn,
std::vector<const VertexTypePos3Normal>& verticesOut,
std::vector<unsigned short>& indicesOut)
{
std::map<VertexTypePos3Normal, int> map;
int indexCounter = 0;
for (auto c_it = verticesIn.cbegin(); c_it != verticesIn.cend(); ++c_it) {
bool newlyAdded = map.insert(std::pair<VertexTypePos3Normal, int>(*c_it, indexCounter)).second;
if (newlyAdded) {
verticesOut.push_back(*c_it);
//map.insert(std::pair<VertexTypePos3Normal, int>(*c_it, indexCounter));
++indexCounter;
}
indicesOut.push_back(map[*c_it]);
}
}
我在最终版本中使用地图,因为该集合已过时。
这是我的新操作符
bool operator<(const VertexTypePos3Normal& v1, const VertexTypePos3Normal& v2) {
return (std::tie(v1.pos.x, v1.pos.y, v1.pos.z, v1.normal.x, v1.normal.y, v1.normal.z) < std::tie(v2.pos.x, v2.pos.y, v2.pos.z, v2.normal.x, v2.normal.y, v2.normal.z));
}
【问题讨论】:
-
Can't reproduce(这是我能够从您提供给我们的少量信息中得出的示例)。
-
问题在运行时插入到集合中。对不起,如果我提供的信息不够。我添加了插入集合的方法。如果问题现在提供更多信息,请重新投反对票。
-
断言不一定是由您的
operator<触发的,我认为这是一条通用消息,表明您的比较谓词在某种程度上无效,可能是因为您的operator==不符合strict weak ordering要求(非自反性)。
标签: c++ stl set operator-overloading