2017-08-25 91 views
0

我有一個數據庫類應該提供一個模板方法來返回代表表格的資源庫對象。每個存儲庫只能存在一次。我發現this的例子,但我想有一個內置的緩存。具有內置緩存的C++對象工廠 - 陰影模板參數

database.h頭看起來是這樣的:

class Database 
{ 
public: 
    Database(const char *connectionString); 
    template<typename T> shared_ptr<class T : RepositoryBase> GetRepository(); 

private: 
    sqlite3* _connection; 
    map<string, RepositoryBase> _repositoryCache; 
}; 

GetRepository方法類似於實現:

template<typename T> shared_ptr<class T : RepositoryBase> Database::GetRepository() 
{ 
    string name = typeid(T).name(); 

    if(_repositoryCache.count(name) == 0) 
    { 
    _repositoryCache[name] = shared_ptr<T>(new T(_connection)); 
    } 

    return _repositoryCache[name]; 
} 

我想叫它像:

// SampleRepository is derived from RepositoryBase 
shared_ptr<SampleRepository> sampleRepo = GetRepository<SampleRepository>(); 

當我編譯我得到的錯誤:

error : declaration of 'T' shadows template parameter 

我需要在模板方法中更改以避免影響任何模板參數?


UPDATE

後NathanOliver的建議模板方法是這樣的:

template<typename T, typename enable_if<is_base_of<RepositoryBase, T>::value>::type* = nullptr> shared_ptr<T> Database::GetRepository() 
{ 
    string name = typeid(T).name(); 

    if(_repositoryCache.count(name) == 0) 
    { 
    _repositoryCache[name] = shared_ptr<T>(new T(_connection)); 
    } 

    return _repositoryCache[name](); 
} 

這一次,我得到的錯誤:

error : template parameter redefines default argument 

它指向nullptr在模板簽名。


更新2

我試過基於從@NathanOliver給出了答案參數的幾種組合。我仍然得到錯誤:

1>C:\..\Database.cpp(65,98): error : template parameter redefines default argument 
1>template<typename T, typename std::enable_if<std::is_base_of<RepositoryBase, T>::value>::type* = nullptr> std::shared_ptr<T> Database::GetRepository() 
1>                        ^
1>C:\..\Database.h(25,108) : note: previous default template argument defined here 
1>   template<typename T, typename std::enable_if<std::is_base_of<RepositoryBase, T>::value>::type* = nullptr> std::shared_ptr<T> GetRepository(); 
1>                           ^

爲了更好地理解,我還添加了存儲庫基類。

class RepositoryBase 
{ 
public: 
    RepositoryBase(sqlite3* connection); 
    virtual string GetTableName() = 0; 

    protected: 
    sqlite3* _connection; 
}; 
+0

是'數據庫'模板?如果是的話,模板'部分是什麼樣子? – NathanOliver

+0

否。它只是您可以在數據庫頭文件中看到的「GetRepository」函數模板。 –

+1

你想用'shared_ptr '來做什麼?你是否想說'T'需要從'RepositoryBase'派生? – NathanOliver

回答

4

的這裏的問題是,

template<typename T> shared_ptr<class T : RepositoryBase> GetRepository(); 

無效的語法在C++中。如果你想限制TRepositoryBase或派生自RepositoryBase那麼你需要在template<typename T>部分做到這一點。我們所做的是添加一個T類型的檢查,如果檢查失敗,那麼編譯器將不會生成會導致編譯器錯誤的函數。這看起來像

template<typename T, typename std::enable_if<std::is_base_of<RepositoryBase, T>::value>::type* = nullptr> 
shared_ptr<T> GetRepository(); 
+0

感謝您的回覆。對我來說,它看起來是我想要的。雖然我得到以下錯誤:'錯誤:模板參數重新定義默認參數',它指向模板簽名中的'nullptr'。實現需要在定義的頭部中看起來不同嗎? –

+0

@BrunoBieri應該看起來像:http://coliru.stacked-crooked.com/a/6ba2e0bad6e9f968 – NathanOliver

+0

謝謝你的代碼示例!我仍然無法弄清楚。我得到錯誤'錯誤:模板參數重新定義默認參數'。任何暗示這可能導致什麼? –