当我尝试编译以下代码时:
#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);
}
我收到编译错误。 但是,当我用vector替换set时,因此使用push_back函数而不是insert函数一切正常。谁能解释一下我做错了什么? 谢谢你的建议。
答案 0 :(得分:3)
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;
}
请记住,无论您使用的功能是什么,该功能都必须为您的类型定义strict weak ordering。
答案 1 :(得分:2)
要在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==
。