2012-11-05 33 views
0

這裏是要求:比較具有不同類型值的兩組

我有一個屬性列表。每個屬性都有一個int類型的標籤和一個以下類型的值:(bool,char,string,int,long)。 一些樣本性質:

標籤:1,值: 「一些字符串」
標籤:14,值:真
標籤:20,值:123

還有一個列表的規則。每條規則就像一個屬性,加上以下其中一個運算符:(<,>,< =,> =,==,!=,startsWith)。 startsWith運算符用於檢查一個字符串是否以另一個字符串開頭。

一些樣本規則:

標籤:1,價值: 「你好」,運營商:==
標籤:14,值:真,符:==

每個列表的規則稱爲Criteria並用於驗證屬性列表。如果僅滿足條件的所有規則,則條件驗證屬性列表。例如,上面的兩條規則構成了一個標準。此條件不驗證上述屬性列表,因爲第1條規則強制tag(1)的值等於(==)爲「hello」,而不是。

以下標準:

標籤:1,值: 「一些字符串」,操作者:==
標籤:20,值:100,操作者:>
標籤:20,值: 120,操作者:<

不驗證上述性質也是如此,因爲雖然前兩個規則都滿足時,最後一個規則,這迫使標籤(20)的值小於120是不正確的。因此整個標準不會驗證屬性。
這裏是驗證爲真一個標準:

標籤:1,價值: 「一些」,運營商:startsWith
標籤:14,值:false,運算符:!=
標籤:20 ,值:123,操作者:> =
標籤:20,值:100,操作者:>

到目前爲止我已經提出了下面的代碼。但我卡在StartsWith運營商的執行。也許我應該選擇一種完全不同的方法來解決這個問題。任何意見和幫助將不勝感激!

#include <string> 
#include <iostream> 
#include <set> 
#include <algorithm> 
#include <tr1/memory> 

using namespace std; 

/////////////////// Property Class ////////////////////// 

class Property 
{ 
public: 
    enum Operator 
    { 
     EQ,  // == 
     NEQ, // != 
     GT,  // > 
     GTE, // >= 
     LT,  // < 
     LTE, // <= 
     SW,  // Starts With 
    } mOperator; 

    Property() {}; 
    Property(const int tag, Operator op) 
      : mTag(tag), mOperator(op) {} 
    virtual ~Property() {} 
    virtual void* GetValue() = 0; 
    virtual bool IsEqual(void* value) = 0; 
    virtual bool Compare(void* value, Property::Operator op) = 0; 
    virtual void Print() = 0; 
    int mTag; 
    bool operator<(const Property &property) const 
    { 
     return mTag < property.mTag; 
    } 
}; 
struct PropertyPtrComp 
{ 
    bool operator()(const std::tr1::shared_ptr<Property> lhs, const std::tr1::shared_ptr<Property> rhs) const 
    { 
     return lhs->mTag < rhs->mTag; 
    } 
}; 

/////////////////// TypedProperty Class ///////////////// 

template< typename T > 
class TypedProperty : public Property 
{ 
public: 
    TypedProperty (const int tag, const T& value, Property::Operator op) 
      : Property(tag, op), mValue(value) {} 
    void* GetValue() 
    { 
     return &mValue; 
    } 
    bool IsEqual(void* value) 
    { 
     return *((T*)value) == mValue; 
    } 
    bool Compare(void* value, Property::Operator op) 
    { 
     // cout << "comparing " << *((T*)value) << " with " << mValue << endl; 
     switch (op) 
     { 
      case Property::EQ: 
       return *((T*)value) == mValue; 
      case Property::NEQ: 
       return *((T*)value) != mValue; 
      case Property::GT: 
       return mValue > *((T*)value) ; 
      case Property::LT: 
       return mValue < *((T*)value) ; 
      case Property::SW: 
      { 
       if (typeid((T*)value) == typeid(string*)) 
       { 
       // dont know what to do! 
       //return ((string)mValue).compare(0, ((string*)value)->length(), (string)(*((string*)value))); 
       } 
      } 
      default: 
       return *((T*)value) == mValue; 
     } 
    } 
    void Print() 
    { 
     cout << "Tag: " << mTag << ", Value: " << mValue << endl; 
    } 
    T mValue; 
}; 

///////////////////////////////////////////////////////// 

typedef std::tr1::shared_ptr<Property> PropertyPtr; 

/////////////////// PropertyList Class ///////////////// 

class PropertyList 
{ 
public: 
    PropertyList() {}; 
    virtual ~PropertyList() {}; 
    template <class T> 
    void Add(int tag, T value, Property::Operator op = Property::EQ) 
    { 
     PropertyPtr ptr(new TypedProperty<T>(tag, value, op)); 
     mProperties.insert(ptr); 
    } 
    void Print() 
    { 
     cout << "-----------" << endl; 
     for (set<PropertyPtr>::iterator itr = mProperties.begin(); itr != mProperties.end(); itr++) 
     { 
      (*itr)->Print(); 
     } 
    } 
    set<PropertyPtr, PropertyPtrComp> mProperties; 
}; 

//////////////////// Check Subset /////////////////////// 
/* 
* Checks if subset is included in superset 
*/ 
bool CheckSubset(set<PropertyPtr, PropertyPtrComp> &superset, 
     set<PropertyPtr, PropertyPtrComp> &subset) 
{ 
    if (subset.size() > superset.size() || subset.empty()) return false; 
    typename set<PropertyPtr>::iterator litr = superset.begin(); 
    for (typename set<PropertyPtr>::iterator ritr = subset.begin(); ritr != subset.end();) 
    { 
     while (litr != superset.end()) 
     { 
      PropertyPtr lProp = (PropertyPtr)*litr; 
      PropertyPtr rProp = (PropertyPtr)*ritr; 
      if (lProp->mTag == rProp->mTag) 
      { 
       if (lProp->Compare(rProp->GetValue(), rProp->mOperator)) 
       { 
        litr++; 
        break; 
       } 
       return false; 
      } 
      else 
      { 
       litr++; 
      } 
     } 
     ritr++; 
     if (litr == superset.end() && ritr != subset.end()) return false; 
    } 
    return true; 
} 

int main() 
{ 
    PropertyList properties; 

    string s = "bye"; 

    properties.Add(1, "hello"); 
    properties.Add(2, 12); 
    properties.Add(3, 34); 
    properties.Add(4, "bye"); 

    properties.Print(); 

    PropertyList ruleSet1; 
    ruleSet1.Add(2, 12, Property::EQ); 
    ruleSet1.Add(4, "bye", Property::EQ); 

    ruleSet1.Print(); 

    if(CheckSubset(properties.mProperties, ruleSet1.mProperties)) 
    cout << "RuleSet1 verified!" << endl; // <<<< should be printed 
    else 
     cout << "RuleSet1 NOT verified!" << endl; 


    PropertyList ruleSet2; 
    string hel = "hel"; 
    ruleSet2.Add(1, hel, Property::SW); 
    ruleSet2.Add(2, 13, Property::NEQ); 

    ruleSet2.Print(); 

    if (CheckSubset(properties.mProperties, ruleSet2.mProperties)) 
     cout << "RuleSet2 verified!" << endl; // <<<< should be printed 
    else 
     cout << "RuleSet2 NOT verified!" << endl; 


} 
+0

我認爲代碼牆讓代碼評論SE更有意義。 –

+0

我在這裏沒有看到問題。標題中可能藏有一個,但我不確定它是什麼。但是,答案似乎是,您希望提供比較運算符或哈希函數,並使用它來提供集合運算。 – eh9

回答

2

不要使用void *,嘗試boost :: variant。構建在每個運營商上運行的測試仿函數。您比較的價值是另一個變體。您可能需要仿函數的函子,因此您可以在兩個變體之間進行任何想要執行的轉換。

這將類型和存儲與每種類型的算法分開。和boost一樣,變體類型比你更好。

你的測試,然後成了一對標籤和std::function<bool(boost::variant<int,long,string,etc>)>這確實考驗。

一個例子,只有兩種類型。

開始與地圖從int變體:typedef std::map<int, boost::variant<int, string>> MyMap

現在進行測試。一個測試是3件事 - 一個id,一個值(這是一個變體)和一個測試來比較這個變體和數據。如果我們不允許字符串和整數相等,我們得到:

template<typename T> 
struct CheckOneTypeEquality 
{ 
    T const* value; 
    bool operator()(T const& other) const 
    { 
    return other == *value; 
    } 
    template<typename U> 
    bool operator()(U const& other) const 
    { 
    return false; 
    } 
    CheckOneTypeEquality(T const& value_):value(&value_) {} 
}; 

template<typename Variant> 
struct TestVariantEquality 
{ 
    Variant* v; 
    struct FindRightToCompare 
    { 
    Variant* other; 
    template<typename T> 
    bool operator()(T const& value) const 
    { 
     return apply_visitor(*other, CheckOneTypeEquality<T>(value)); 
    } 
    FindRightToCompare(Variant const& other_): other(other_) {} 
    }; 

    bool operator()(Variant const& other) const 
    { 
    return apply_visitor(*v, FindRightToCompare(other)); 
    } 
}; 

...這不編譯時檢查相等比較。所有上述操作在左,右兩個操作數雙apply_visitorCheckOneTypeEquality<T>T比賽左操作數的類型,而右操作數傳過來的Uoperator()

在這種情況下,我們只支持同類型的平等 - 如果我們想要讓intlong比較,我們可以只適當專門的CheckOneTypeEquality<T>::operator()<U>

我們也可以通過在非模板類型中包裝CheckOneTypeEquality並將它傳遞給TestVariantEquality類,它除了安排我們正在比較的兩種類型的雙重派發外什麼也不做。這意味着TestVariantEquality(以及更通用的版本,它將最終的比較函子作爲模板參數)可以寫入一次,並且您只需爲每個比較測試編寫一個等效的函子。

免責聲明:以上代碼沒有被我編譯,並基於關閉在線文檔的快速閱讀。在上面的代碼中沒有使用名稱空間,因爲我很懶,但是一切基本上都是從stdboost或子命名空間boost

注意TestVariantEquality(或類似的函子)可以被用來初始化一個std::function<bool(Variant<...> const&)>。所以產生測試函數的函數應該返回std::function<bool(Variant<...> const&)>,並且內部可以執行上述類型的東西。

properties應該是一個std::map<int, boost::variant<blah blah>>。你的測試應該是std::multimap<int, std::function<bool(boost::variant<blah blah> const&)>>

將您正在測試的數據加載到屬性中。使用上述技術構建測試。不需要虛函數,不需要void指針,並且所有內容都是編譯時類型。

+0

如果你能發表更詳細的答案,我將不勝感激 – Meysam

+0

你不瞭解哪些部件? 'boost :: variant'在網絡上有一堆文檔,你理解它們嗎?你知道一個函數是什麼嗎? – Yakk

+0

我知道一個函數是什麼,我只是無法繞過一個使用變體和函數來實現我的目的的解決方案。 – Meysam

相關問題