没有详细说明为什么我在做我正在做的事情让我描述这个问题。
我使用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调用我的运算符&lt;但结果不正确,因为该集合主要只包含1个值,尽管该向量包含大约15个不同的值。
以下是插入集合的方法:
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,因此也不是运算符&lt;,STL中有一个断言错误(使用VC编译器)_DEBUG_ERROR2(“invalid operator&lt;”,_ File,_Line);
所以实际上我有两个问题:
1。)为什么我的运营商&lt;没有按照预期使用std :: less。
2.)运营商如何&lt;当它甚至没有被调用时触发一个断言。
编辑:感谢所有信息。看起来我完全误解了严格的弱排序。使用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]);
}
}
我在最终版本中使用地图,因为该集合已过时。
这是我的新运营商&lt;
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));
}
答案 0 :(得分:4)
有序关联容器需要strict weak ordering关系。所需的属性包括反对称性,即cmp(x,y)
暗示!cmp(y,x)
。您对operator<
的定义不满足此属性。
此外,相等(或等价)可以定义为!(cmp(x,y)||cmp(y,x))
,通常使用此代替x==y
。也就是说,即使您没有明确使用它,也可能会调用operator<
。
答案 1 :(得分:1)
您的运营商&lt;是完全错的。
你可能想要:
bool operator<(const VertexTypePos3Normal& v1, const VertexTypePos3Normal& v2) {
if(v1.pos.x < v2.pos.x) return true;
else if(v1.pos.x == v2.pos.x) {
if(v1.pos.y < v2.pos.y) return true;
else if(v1.pos.y == v2.pos.y) {
if(v1.pos.z < v2.pos.z) return true;
else if(v1.pos.z < v2.pos.z) {
if(v1.normal.x < v2.normal.x) return true;
else if(v1.normal.x == v2.normal.x) {
if(v1.normal.y < v2.normal.y) return true;
else if(v1.normal.y < v2.normal.y) {
if(v1.normal.z < v2.normal.z) return true;
}
}
}
}
}
return false;
}
注意:对于glm :: vec3,应该分成两个较少的函数调用(bool less(const glm :: vec3&amp;,const glm :: vec3&amp;);)