我有一个基数std::vector
和一个std::initializer_list<Attribute*>
,它是函数的参数,由Attribute
类的派生类组成。
class Attribute {};
class Place : public Attribute {};
class Time : public Attribute {};
class Way: public Attribute {};
Place* place = new Place();
Time* time = new Time();
Way* way = new Way();
Place* place2 = new Place(...);
Time* time2 = new Time(...);
auto baseList = std::vector<Attribute*>({ place, time, way })
void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l);
updateBaseList
必须做的是,如果l
中元素的类型等于baseList
中的元素的类型,则使用baseList
中的值更新l
中的值{1}}。如果baseList
中未遇到该类型,则必须添加该类型。
请注意,搜索的类型不是Attribute*
,而是派生类。
我的尝试
void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l) {
bool found;
for (auto listIt = l.begin(); listIt != l.end(); ++listIt) {
found = false;
for (auto attrIt = baseList.begin(); attrIt != baseList.end(); ++attrIt) {
if (typeid(**listIt) == typeid(**attrIt)) {
*attrIt = *listIt;
found = true;
break;
}
}
if (!found) {
baseList.push_back(*listIt);
}
}
}
但typeid(**listIt)
和typeid(**attrIt)
始终返回Base
。
目标
如果我调用updateBaseList(baseList, { time2, place2 })
baseList应为{ place2, time2, way }
答案 0 :(得分:3)
您需要使类层次结构具有多态性。这样做的一个好方法是添加virtual ~Attribute() { }
析构函数:
struct Attribute
{
virtual ~Attribute() { }
};
您的代码然后works as expected:
{
auto baseList = std::vector<Attribute*>({ place0, time0 });
updateBaseList(baseList, {place2, time2, way0});
assert(baseList[0] == place2);
assert(baseList[1] == time2);
assert(baseList[2] == way0);
assert(baseList.size() == 3);
updateBaseList(baseList, {place0});
assert(baseList[0] == place0);
assert(baseList[1] == time2);
assert(baseList[2] == way0);
assert(baseList.size() == 3);
}
不相关,但您可以使用C ++ 11 range-for循环更容易阅读baseList
的实现:
void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l)
{
for (auto& litem : l)
{
bool found = false;
for (auto& attr : baseList)
{
if (typeid(*litem) != typeid(*attr)) continue;
attr = litem;
found = true;
break;
}
if (!found)
{
v.push_back(litem);
}
}
}
您还可以利用标准算法来避免有状态found
变量:
void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l)
{
for (auto& litem : l)
{
const auto found = std::find_if(std::begin(v), std::end(v), [&](Attribute* p)
{
return typeid(*litem) == typeid(*p);
});
if (found == std::end(v))
{
v.push_back(litem);
}
else
{
*found = litem;
}
}
}