Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
420 views
in Technique[技术] by (71.8m points)

stl - problems with c++ set container

When I try to compile the following code:

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

    }

I get the compilation error. However, when I replace set by vector and hence use the the push_back function instead of insert function everything works fine. Could anyone explain me what am I doing wrong? Thanks in advice.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

std::set stores its values in a sorted binary tree, so it needs to know how to compare the values it holds. By default it uses std::less as a comparison function, which for un-specialized user defined types tries to call operator<. So, the easiest way to tell the set how to compare your objects is to define an operator< for your class:

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

However, there are also other ways of telling std::set how to compare your type. One is to specialize the std::less template for your class:

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

Another is to replace the default comparison type with a function with the correct signature, or a class that has an operator() defined with the correct signature. This is where things start to get ugly.

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

Keep in mind that whatever less-than function you use, that function must define a strict weak ordering for your type.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...