2009-02-20 74 views
13

我試圖聲明和Column類,其中具有私有的std::map,其值指向模板化的Column。事情是這樣的:C++ std ::模板類值映射

template <typename T> 
class DataType { 
    private: 
    T type; 
}; 
template <typename T> 
class Field { 
    private: 
    T value; 
    DataType<T> value; 
}; 
class Row { 
    private: 
    std::map<unsigned long,Field*> column; 
}; 

好吧,我想在原則上類不應該知道,我們想用,即無論是哪一種Field(或Column)一Field<int>在第1列或Field<double>第2列。但我不確定Row::column聲明的正確語法是什麼,或者如果std::map在這個意義上是有限的,我應該使用別的東西。

我喜歡你的建議,並提前感謝你。

+0

那麼問題是什麼? – 2009-02-20 10:44:04

+1

您不必將您的代碼轉換爲html。按照原樣放入4字符縮進。 – 2009-02-20 10:48:39

回答

22

Field單獨不是一種類型,而是一個可以生成一系列類型的模板,如Field<int>Field<double>。所有這些領域都是不相關的,以至於這個領域是以某種方式從另一個領域衍生出來的。所以你必須在所有這些生成的類型之間建立一些關係。一種方法是使用通用的非模板基類:

class FieldBase { }; 

template <typename T> 
class Field : public FieldBase { 
    private: 
    T value; 
    DataType<T> type; 
}; 
class Row { 
    private: 
    std::map<unsigned long,FieldBase*> column; 
}; 

並考慮在代碼中使用智能指針而不是原始指針。無論如何,現在問題在於類型信息丟失 - 無論您指向Field<double>還是Field<int>都不再知道,只能通過在由模板設置的基礎中保留某種類型的標誌來檢測派生類 - 或通過詢問RTTI使用

dynamic_cast<Field<int>*>(field) != 0 

但這是醜陋的。特別是因爲你想要的是有價值的語義。即,您希望能夠複製您的行,並且它會複製其中的所有字段。而且,當存儲雙精度數據時,您希望獲得雙精度值,而不是先使用RTTI來破解派生類型。

這樣做的一種方法是使用歧視聯盟。這基本上是一些任意類型的聯合,另外還有一個類型標誌,它存儲當前存儲在該字段中的值(例如是否爲double,int,...)。例如:

template <typename T> 
class Field { 
    private: 
    T value; 
    DataType<T> type; 
}; 
class Row { 
    private: 
    std::map<unsigned long, 
      boost::variant< Field<int>, Field<double> > > 
     column; 
}; 

boost :: variant爲您完成所有工作。您可以使用訪問使其使用正確的過載來調用仿函數。看看它的manual

1
  1. 你在那裏得到一個錯誤:你必須在字段中「值」成員(其中一個應該是「類型」)。
  2. 請不要在地圖的值中保留原始指針。使用boost::shared_ptr
  3. 此外,你應該有一個很好的理由來編寫這樣的類,那裏已經有大量的DB /表處理代碼,你可以使用它們。因此,如果適用,請考慮使用現有的東西,而不是編寫自己的表格處理代碼。

現在,回答你的問題:),字段可以從所有數據類型共享的公共基類繼承。通過這種方式,諸如列映射之類的容器可以將指針(使共享指針)保留爲模板類實例化的派生對象。

0

A Row< int, float, int>是真的不同於Row<int, std::string>。 顯然,Row<int,float,int>.field<0>應該是Field<int>,而Row<int,float,int>.field<1>應該是Field<float>。而Row<int,float,int>.field<3>是編譯器錯誤。

最簡單的方法是使用Boost。 Loki開創了大量的情報(見Modern C++ Design, by Andrei Alexandrescu),但Boost更現代化和更好的支持。

通常情況下,您不會遍歷字段 - 每個字段都有其自己的類型。但是,你確實需要一個FieldBase。如果您需要這樣的界面,則可能還需要在內部將這些字段存儲爲boost::array<FieldBase, N>(即,Row<int,float,int>具有boost::array<FieldBase, 3>)。儘管如此,你應該永遠不需要dynamic_castFieldBase*。這是一個運行時測試,並且您在編譯時始終知道每個Field<T>的確切T