【问题标题】:problems with c++ set containerc++ set 容器的问题
【发布时间】:2013-02-09 03:27:46
【问题描述】:

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

    #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);

    }

我得到编译错误。 但是,当我用向量替换 set 并因此使用 push_back 函数而不是 insert 函数时,一切正常。谁能解释我做错了什么? 感谢您的建议。

【问题讨论】:

  • 如果你不关心排序,你可能想试试std::unordered_set这在我的脑海里。
  • @chris 使用std::unordered_set 可能需要更多的工作,因为您必须提供哈希和相等运算符。
  • @Rapptz,没错,虽然在我看来,这里的排序并不突出。
  • 不定义排序(operator &lt;(const Property&amp;),标准std::set 无法确定元素的身份(顺便说一句,这是使用(!(left &lt; right) &amp;&amp; !(right &lt; left)) 完成的,因此请确保您的顺序一致) . std::pair&lt;&gt; 模板已经定义了最常用的顺序比较器,所以除非您有特定的理由,否则您可以通过简单地将Property 作为正式定义来轻松解决您的问题而是只使用typedef std::pair&lt;string,string&gt; Property; 我猜,但是,您需要不区分大小写的标签比较。

标签: c++ stl set


【解决方案1】:

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

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;
}

请记住,无论您使用什么小于函数,该函数都必须为您的类型定义一个strict weak ordering

【讨论】:

  • 我将模板从PropertyLess移动到operator(),这样你就不必复制参数std::set&lt;Property&lt;std::string, std::string&gt;, PropertyLess&gt; set3;
【解决方案2】:

要向std::set 中插入内容,您需要定义operator&lt;

例如,这在 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==

【讨论】:

  • 你对 operator
  • 你不需要 operator&lt;,你也可以提供一个比较器。
猜你喜欢
  • 2011-04-08
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 2013-08-19
  • 2019-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多