2012-09-05 55 views
1

我有一組類用於爲序列化準備數據。所有這些都來自基類cBase,它不包含與問題相關的任何內容。在派生類中的模板存在問題

在派生類有:

class cValue: public cBase 
{ 
public: 
    cValue(){} 
    template< class T > void set(const T & value){ data_ = value; } 

protected: 
    QVariant data_; 
}; 

這是用於保持簡單值像字符串或數字的類。這裏是一個類來表示一個對象(基本的東西,可以持「名稱 - 值」對:

class cObject: public cBase 
{ 
public: 
    cObject(){} 

    void addAttribure(const QString & name, cBase * value) 
    { 
     if(attributes_.contains(name)) 
      delete attributes_[name]; 
     attributes_[name] = value; 
    } 

    template< class T > void addAttribure(const QString & name, const T & value) 
    { 
     cValue * tmp = new cValue(); 
     tmp->set(value); 
     addAttribure(name, tmp); 
    } 
protected: 
    QMap< QString, cBase * > attributes_; 
}; 

這樣做的目的是爲了能夠既與已經創建的對象添加屬性:addAttribute(someName, someObject);與原始值:addAttribute("name", 42);

現在,因爲它是,這段代碼編譯不過,如果我嘗試創建這樣一個對象:

cValue *tmp = new cValue(); 
tmp->set(42); 
cObject obj; 
obj.addAttribure("The Answer", tmp); 

,我發現了以下錯誤:

/usr/include/qt4/QtCore/qvariant.h:429:12: error: 'QVariant::QVariant(void*)' is private 
../../source/private/../include/MyClasses.h:36:51: error: within this context 

錯誤出現在cValueset()函數聲明的行上。 現在,如果我從功能去除addAttribute()的模板版本,然後將完全相同的代碼到我的主:

cObject obj; 
cValue * tmp = new cValue(); 
tmp->set(42); 
obj.addAttribure("The Answer", tmp); 

它工作正常。我認爲它與addAttribute()set()函數都是模板化的事實有關,但我無法理解如何解決此問題,或至少如何制定解決方法。

:如果可能的話,我想使自己的模板類,只有功能。

+0

難道這是一個含糊不清的問題,因爲'addAttribure(常量QString的& name,cBase * value)'與'addAttribure(const QString&name,const T&value)'相同時''T == cBase *'。如果你明確指出'tmp-> set (42)'? – cmannett85

+0

@ cmannett85,你幾乎是對的,這確實是一個模糊的問題,但我不得不改變的路線是'addAttribure(name,tmp);'在模板化的'addAttribute()'函數中,我用一個更明確的' addAttribure(名稱,static_cast (tmp));'。現在正在工作。發佈這個答案,我會接受它。 – SingerOfTheFall

回答

0

問題在於,當使用cValue時,由於cValuecBase派生,所以您期望編譯器調用addAttribure(const QString& name, cBase* value)。但由於它們不完全匹配,因此編譯器會調用addAttribure<cValue*>(const QString& name, const cValue* value)

這就是爲什麼(在您的評論中指出)呼籲addAttribure(name, static_cast<cBase*>(tmp))工作。

+2

重載函數幾乎總是比專門模板更好(在這裏有很多與此相關的問題)。不,當'T' ='cBase *'時沒有歧義。在這種情況下,編譯器選擇顯式函數而不是模板。 – Gorpik

+0

你說得對,我會編輯我的答案。 – cmannett85

0

也許在識別類型時存在問題。我和QT有類似的問題,但前一段時間。也許你應該嘗試

template< class T > void set(const T & value) 
{ 
    data_ = QVariant::fromValue(value); 
    // or data_.setValue(value) 
} 
2

這個問題以及您的修補程序使用轉換工作的原因是編譯器僅在您使用其簽名的參數類型調用它時才選擇非模板化函數。在這種情況下,您沒有使用cBase*,而是使用cObject*。當然,後者可以自動轉換爲前者,但編譯器會發現它可以實例化模板以創建與參數完全匹配的函數,因此它會選擇該函數。

您可以使用自己投去:

addAttribure(name, static_cast<cBase *>(tmp)); 

,或者你可以直接使用一個基類指針,以避免投:

cBase* pBase = tmp; 
addAttribure(name, pBase);