2017-01-28 10 views
3

私はstd::vectorという基底とstd::initializer_list<Attribute*>という1つの基底を持っていますが、それはAttributeクラスの派生クラスからなる関数の引数です。 lの要素の型がlの一つとbaseListでその値を更新し、baseListの1に等しい場合既存の型を置き換え、新しい型を追加する

updateBaseListがしなければならない何
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); 

は、あります。タイプが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 }

答えて

2

でなければなりません。これを行うには良い方法は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を使って読むことがbaseListの実装が容易になります++ 11範囲ループ:

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; 
     } 
    } 
} 
関連する問題