c++设置容器的问题

problems with c++ set container

本文关键字:问题 设置 c++      更新时间:2023-10-16

当我尝试编译以下代码时:

    #include <iostream>
    #include <set>
    #include <vector>
    using namespace std;
    template <class T, class S> 
    class Property
    {
    public:
        pair<T,S> p;
        Property(T t, S s) { p = make_pair(t,s);}
    };
    int main()
    {
    set< Property<string, string> > properties;
    Property<string, string> name("name", "Andy");
    properties.insert(name);
    }

我得到了编译错误。然而,当我用向量替换集合,因此使用push_back函数而不是insert函数时,一切都很好。有人能解释一下我做错了什么吗?谢谢你的建议。

std::set将其值存储在一个排序的二进制树中,因此它需要知道如何比较它所持有的值。默认情况下,它使用std::less作为比较函数,对于非专用的用户定义类型,它尝试调用operator<。因此,告诉集合如何比较对象的最简单方法是为类定义一个operator<

template <class T, class S> 
class Property
{
public:
    pair<T,S> p;
    Property(T t, S s) { p = make_pair(t,s);}
    bool operator<(const Property<T,S>& rhs) const
    {
        return p < rhs.p;
    }
};

然而,还有其他方法可以告诉std::set如何比较您的类型。一种是为您的类专门化std::less模板:

namespace std {
template<typename T,typename S>
struct less<Property<T, S> >
{
    bool operator()(const Property<T, S>& lhs, const Property<T,S>& rhs) const
    {
        return lhs.p < rhs.p;
    }
};
}

另一种方法是用具有正确签名的函数或具有使用正确签名定义的operator()的类来替换默认比较类型。这就是事情开始变得丑陋的地方。

// Comparison function
template<typename T, typename S>
bool property_less_function(const Property<T,S>& lhs, const Property<T,S>& rhs)
{
    return lhs.p < rhs.p;
}
// Comparison functor
template<typename T, typename S>
struct PropertyLess
{
    bool operator()(const Property<T,S>& lhs, const Property<T,S>& rhs) const
    {
        return lhs.p < rhs.p;
    }
};
int main()
{
    // Set using comparison function. 
    // Have to pass the function pointer in the constructor so it knows
    // which function to call. The syntax could be cleaned up with some
    // typedefs.
    std::set<Property<std::string, std::string>, 
        bool(*)(const Property<std::string, std::string>&, 
                const Property<std::string, std::string>&)> 
            set1(&property_less_function<std::string, std::string>);
    // Set using comparison functor. Don't have to pass a value for the functor
    // because it will be default constructed.
    std::set<Property<std::string, std::string>, PropertyLess<std::string, std::string> > set2;
}

请记住,无论您使用的函数是什么,该函数都必须为您的类型定义严格的弱排序。

为了在std::set中插入一些内容,您需要定义operator<

例如,这在GCC 4.7.2:上编译良好

#include <iostream>
#include <set>
#include <vector>
using namespace std;
template <class T, class S> 
class Property
{
public:
    pair<T,S> p;
    Property(T t, S s) { 
        p = make_pair(t,s);
    }
    bool operator<(const Property& p2) const {
        //Something naive..
        return p < p2.p; 
    }
};
int main()
{
set< Property<string, string> > properties;
Property<string, string> name("name", "Andy");
properties.insert(name);
}

另一种选择是使用std::unordered_set,尽管这需要为密钥提供哈希并定义operator==