运算符无效<使用std :: equal_to

时间:2014-02-02 16:04:12

标签: c++ stl set operator-overloading

没有详细说明为什么我在做我正在做的事情让我描述这个问题。

我使用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));
        }

2 个答案:

答案 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;);)