C++ 为什么set::find不是模板?
使用C++ 为什么set::find不是模板?,c++,stl,c++11,std,C++,Stl,C++11,Std,使用中的模板函数,您可以执行以下操作 struct foo { int bar, baz; }; struct bar_less { // compare foo with foo bool operator()(const foo& lh, const foo& rh) const { return lh.bar < rh.bar; } template<typename T> // comp
中的模板函数,您可以执行以下操作
struct foo
{
int bar, baz;
};
struct bar_less
{
// compare foo with foo
bool operator()(const foo& lh, const foo& rh) const
{
return lh.bar < rh.bar;
}
template<typename T> // compare some T with foo
bool operator()(T lh, const foo& rh) const
{
return lh < rh.bar;
}
template<typename T> // compare foo with some T
bool operator()(const foo& lh, T rh) const
{
return lh.bar < rh;
}
};
int main()
{
foo foos[] = { {1, 2}, {2, 3}, {4, 5} };
bar_less cmp;
int bar_value = 2;
// find element {2, 3} using an int
auto it = std::lower_bound(begin(foos), end(foos), bar_value, cmp);
std::cout << it->baz;
}
如果一个人只需调用foos.find(2)
,那将非常有帮助。有没有什么原因使find
不能成为一个模板,接受可以传递给less谓词的所有内容。如果它只是丢失了,为什么它不在C++11中(我想不是)
编辑
主要的问题是为什么它不可能,如果它是可行的,为什么决定标准不提供它。第二个问题是您可以提出解决方法:-)(boost::multi_index_container
刚才我想到了,它提供了从值类型中提取键的功能)
另一个例子是构造值类型的成本更高。键名称
是类型的一部分,不应在地图键中用作副本
struct Person
{
std::string name;
std::string adress;
std::string phone, email, fax, stackoferflowNickname;
int age;
std::vector<Person*> friends;
std::vector<Relation> relations;
};
struct PersonOrder
{
// assume that the full name is an unique identifier
bool operator()(const Person& lh, const Person& rh) const
{
return lh.name < rh.name;
}
};
class PersonRepository
{
public:
const Person& FindPerson(const std::string& name) const
{
Person searchDummy; // ouch
searchDummy.name = name;
return FindPerson(searchDummy);
}
const Person& FindPerson(const Person& person) const;
private:
std::set<Person, PersonOrder> persons_;
// what i want to avoid
// std::map<std::string, Person> persons_;
// Person searchDummyForReuseButNotThreadSafe;
};
struct-Person
{
std::字符串名;
字符串地址;
std::字符串电话、电子邮件、传真、Stackoferflow昵称;
智力年龄;
病媒朋友;
向量关系;
};
结构PersonOrder
{
//假设全名是唯一标识符
布尔运算符()(常数人和左侧、常数人和右侧)常数
{
返回lh.name
key_type是集合容器中定义为key别名的成员类型,key是第一个模板参数,也是容器中存储的元素类型
看
对于用户定义的类型,库无法知道键类型是什么。恰好对于您的特定用例,键类型是
int
。如果使用sets
您可以调用s.find(2)代码>。然而,如果你想搜索集合
并且只想传入一个整数(想想集合的排序在foo
和int
之间是如何工作的),你需要帮助编译器解决这个问题。他们提供了你想要的,但方式与你所考虑的完全不同
实际上,有两种不同的方法:一种是为包含的类构建构造函数,1)可以隐式使用,2)只需要比较所需的元素子集。有了它,你可以搜索食物代码>。您将从2
创建一个临时对象,然后找到该临时对象,但它将是真正的临时对象。您的代码不必显式地(在任何地方)处理它
编辑:我在这里所说的是创建一个与您存储在映射中的类型相同的实例,但是(可能)不初始化(或者初始化为“不存在”)任何未用作“键”的字段。例如:
struct X {
int a; // will be treated as the key
std:::string data;
std::vector<int> more_data;
public:
X(int a) : a(a) {} // the "key-only" ctor
X(int a, std::string const &d, std::vector<int> const &m); // the normal ctor
};
std::set<X> s;
if (s.find(2)) { // will use X::X(int) to construct an `X`
// we've found what we were looking for
}
struct X{
int a;//将被视为密钥
std:::字符串数据;
std::向量更多的数据;
公众:
X(inta):a(a){}//只包含键的向量
X(int a,std::string const&d,std::vector const&m);//正常的向量
};
std::集s;
if(s.find(2)){//将使用X::X(int)构造一个`X`
//我们找到了我们要找的东西
}
是的,当你用单参数构造函数构造你的X
(或者我称之为X)时,你所构造的东西很可能除了搜索之外什么都用不上
结束编辑]
第二个,库提供了更直接的支持,通常比较简单:如果您实际上只使用某些元素子集(可能只有一个)进行搜索,那么您可以创建std::map
,而不是std::set
。使用std::map
,显式/直接支持搜索指定为键类型的任何对象的实例。std::find_如果
在未排序的范围内工作。所以你可以传递任何你想要的谓词
std::set
始终使用Comparator
模板参数(std::less
默认情况下)来维护集合的顺序,以及再次查找元素
因此,如果对std::set::find
进行模板化,则必须只传递一个观察比较器总顺序的谓词
然后再次强调,std::lower_bound
和所有其他在排序范围上工作的算法都已经精确地要求了这一点,因此这不是一个新的或令人惊讶的要求
所以,我想这只是一个疏忽,在std::set
上没有find_if()
(say)。建议使用C++17:)(EDIT::EASTL,他们使用了一个比我好得多的名字:find_as
)
也就是说,你知道吗?排序向量在大多数情况下会更快,并允许您找到std::set
中缺少的灵活性
编辑:正如Nicol所指出的,在和(以及其他地方,我确信)中有这个概念的实现,但鉴于您无法利用它们的主要优势(内置的find()
方法),使用裸std::vector
,您不会损失太多,因为如果您想执行std::find(2)
除了两个foo
s之间的比较外,还必须定义int
如何与foo
进行比较。但是由于int
和foo
是不同的类型,您实际上需要两个附加函数:
bool operator<(int, foo);
bool operator<(foo, int);
bool操作符标准规定std::set::find
具有对数时间复杂度。实际上,这是通过将std::set
实现为二进制搜索树来实现的
bool operator<(int, foo);
bool operator<(foo, int);