为具有特定字段的成员搜索通用范围
Searching a Generic Range for a Member with a Specific Field
这是我的模板函数:
template<class DataStruct>
static bool isPlayerIn(DataStruct players, int id){
for(DataStruct::iterator player = players.begin();
player != players.end(); ++player){
if((*player)->_id == id){
return true;
}
}
return false;
}
我希望它能够让玩家作为矢量和地图,或任何其他 STL。我不能使用算法查找,因为我正在搜索 "player",其内部字段 ID 与给定参数相同。这项工作有什么办法吗?
它抱怨:
(*player)->_id
因为它不知道 player 是 ptr to ptr to Player class.
你的封装有问题,因为函数不知道 DataStruct 是什么,它不能直接 de-reference 它的内部迭代器。
如果您为迭代器实现一个 de-reference 运算符,它将起作用。
在迭代器中添加:
objStored *operator(){
return **this;
}
然后在你的播放器obj中添加一个获取id的方法:
int getId(){
return this->id;
}
而不是 (*player)->_id == id
写 (*player)->getId()
这样,任何 class 在迭代器中包含(以任何方式)支持(以任何方式)getId 方法的对象的对象都将起作用。
如果您使用模板创建通用函数,则不应创建它,因此它仅适用于具有迭代器的 class,该迭代器是指向具有 _id 的玩家的指针成员。
尽量少假设你的对象。
使用C++11,可以轻松使用find_if
with a lambda function:
[=](const typename DataStruct::value_type &v){return v._id == id;}
你会在哪里使用类似
auto has_id = [=](const typename DataStruct::value_type &v){return v._id == id;};
return std::find_if(
std::begin(players),
std::end(players),
has_id) != std::end(players);
既然你要求它,你可以把 lambda 放在一个 isSameID
函数中,如果它会在多个地方使用的话。当您进行代码维护时,它也可能会使它更容易阅读。
template <class ContType>
bool isSameID(ContType cont, int id) {
auto found = find_if(begin(cont), end(cont), [id] (auto item) {
return item->_id == id;
});
return found != end(cont);
}
此函数假定已传递容器并且您使用的是 c++14。
更新 1:
使其同时适用于 map
和 vector
的最快方法是将 _id
检索从函数中分离出来,让编译器选择正确的方法来获取 [=15] =] 对于给定的容器类型。我还根据您的要求删除了 auto
并切换为通过 const&
传递容器以避免复制:
int GetID(const pair<int, Player*>& item) {
return item.second->_id;
}
int GetID(Player* item) {
return item->_id;
}
template <class ContType>
bool isSameID(const ContType& cont, int id) {
typename ContType::const_iterator found = find_if(begin(cont), end(cont),
[id] (typename ContType::value_type item) {
return GetID(item) == id;
});
return found != end(cont);
}
这是我的模板函数:
template<class DataStruct>
static bool isPlayerIn(DataStruct players, int id){
for(DataStruct::iterator player = players.begin();
player != players.end(); ++player){
if((*player)->_id == id){
return true;
}
}
return false;
}
我希望它能够让玩家作为矢量和地图,或任何其他 STL。我不能使用算法查找,因为我正在搜索 "player",其内部字段 ID 与给定参数相同。这项工作有什么办法吗?
它抱怨:
(*player)->_id
因为它不知道 player 是 ptr to ptr to Player class.
你的封装有问题,因为函数不知道 DataStruct 是什么,它不能直接 de-reference 它的内部迭代器。 如果您为迭代器实现一个 de-reference 运算符,它将起作用。
在迭代器中添加:
objStored *operator(){
return **this;
}
然后在你的播放器obj中添加一个获取id的方法:
int getId(){
return this->id;
}
而不是 (*player)->_id == id
写 (*player)->getId()
这样,任何 class 在迭代器中包含(以任何方式)支持(以任何方式)getId 方法的对象的对象都将起作用。
如果您使用模板创建通用函数,则不应创建它,因此它仅适用于具有迭代器的 class,该迭代器是指向具有 _id 的玩家的指针成员。 尽量少假设你的对象。
使用C++11,可以轻松使用find_if
with a lambda function:
[=](const typename DataStruct::value_type &v){return v._id == id;}
你会在哪里使用类似
auto has_id = [=](const typename DataStruct::value_type &v){return v._id == id;};
return std::find_if(
std::begin(players),
std::end(players),
has_id) != std::end(players);
既然你要求它,你可以把 lambda 放在一个 isSameID
函数中,如果它会在多个地方使用的话。当您进行代码维护时,它也可能会使它更容易阅读。
template <class ContType>
bool isSameID(ContType cont, int id) {
auto found = find_if(begin(cont), end(cont), [id] (auto item) {
return item->_id == id;
});
return found != end(cont);
}
此函数假定已传递容器并且您使用的是 c++14。
更新 1:
使其同时适用于 map
和 vector
的最快方法是将 _id
检索从函数中分离出来,让编译器选择正确的方法来获取 [=15] =] 对于给定的容器类型。我还根据您的要求删除了 auto
并切换为通过 const&
传递容器以避免复制:
int GetID(const pair<int, Player*>& item) {
return item.second->_id;
}
int GetID(Player* item) {
return item->_id;
}
template <class ContType>
bool isSameID(const ContType& cont, int id) {
typename ContType::const_iterator found = find_if(begin(cont), end(cont),
[id] (typename ContType::value_type item) {
return GetID(item) == id;
});
return found != end(cont);
}