Without going into much details why I´m doing what I´m doing let me describe the issue.
Im using a std::set for storing unique objects of a struct called VertexTypePos3Normal.
The struct is defined as following:
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
Per default std::set uses std::less as comparison function.
So I first declared my set as std::set<VertexTypePos3Normal> set;
The elements inserted into the set are stored in a std::vector that is not containing unique values (looping over the vector).
Using std::less called my operator< but the result was not correct as the set contained mostly only 1 value although the vector contained about 15 different ones.
Here is the method inserting into the set:
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]);
}
}
So I was about to try out std::equal_to instead of std::less and wrote operator==. Now the weird stuff started:
Although I´m not calling std::less anymore and therefore also not operator<, there is an assertion error in STL (using VC compiler) _DEBUG_ERROR2("invalid operator<", _File, _Line);
So actually i got two questions:
1.) Why is my operator < not working with std::less as it is supposed to.
2.) How can operator< trigger an assertion when it is not even called.
EDIT: Thanks for all information. Looks like I totally missunderstood strict weak ordering. Using std::tie taking care of it solved my problem. Here is the updated code:
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]);
}
}
Im using a map in the final version as the set is obsolete.
Here is my new operator<
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));
}