2015-07-22 118 views
9

我想將CRTP pattern與某些鎖定機制結合使用以在多線程環境中進行訪問同步。非模板錯誤的模板定義

我的代碼如下所示:

//-- CRTP base class with some sync/lock mechanism 
template<typename T, typename SYNC> 
struct Base { 
    static std::unordered_map<int, std::string> s_map; 
    static SYNC s_sync; 
}; 

//-- derived class using CRTP 
template<typename SYNC> 
struct ProductX : public Base<ProductX<SYNC>, SYNC> {}; 

//-- static initialisation 
template<typename SYNC> 
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { 
    { 1, "value_1" }, 
    { 2, "value_2" } 
} 

但是我得到

error: template definition of non-template std::unordered_map<int, std::basic_string<char> > Base<ProductX<SYNC>, SYNC>::s_map

編譯時。

對靜態初始化s_map引發錯誤。有人能指出我做錯了什麼嗎?

+0

@Deduplicator - 這不是你標記的內容的重複。如果重複的東西,那麼這一個:http://stackoverflow.com/questions/13404695/c-how-to-initialize-static-variables-of-a-partial-template-specialization –

回答

0

C++允許這樣的:

template<typename SYNC> 
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { }; 

僅與相應的部分模板類專門化。要做到這些,請查看Columbo和n.m.的回覆。下面的用戶。然而,缺點是您必須重新定義您以這種方式創建的每個ProductX類的所有內容。 IE瀏覽器。在我的情況下,如果我想創建類ProductX,ProductY,ProductZ,我將不得不爲它們中的每一個定義部分特化,包括所有成員函數等,這不是很實用的恕我直言。

如果我們不想寫全班專業化,我們必須使用靜態變量,沒有規範的模板定義:

template<typename T, typename SYNC> 
std::unordered_map<int, std::string> Base<T, SYNC>::s_map { }; 

或完全專用的模板定義:

struct NoSync { }; 
template<typename NoSync> 
std::unordered_map<int, std::string> Base<ProductX<NoSync>, NoSync>::s_map { }; 

這裏是完整的模板專業化的完整示例:

//-- CRTP base class with some sync/lock mechanism 
template<typename T, typename SYNC> 
struct Base { 
    static std::unordered_map<int, std::string> s_map; 
    static SYNC s_sync; 
    static std::string& value_name1(int value) { return s_map[value]; } 
}; 

//-- derived class using CRTP 
template<typename SYNC> 
struct ProductX : public Base<ProductX<SYNC>, SYNC> {}; 

struct NoSync {}; 

//-- static initialisation 
template<> 
std::unordered_map<int, std::string> Base<ProductX<NoSync>, NoSync>::s_map { 
    { 1, "value_1" }, 
    { 2, "value_2" } 
}; 

int main() { 
    ProductX<NoSync> p; 
    std::cout << "Value: " << p.s_map[1] << "\n"; 
    std::cout << "Value: " << p.value_name1(2) << "\n"; 
} 

這一個將編譯好。

我想感謝Columbo和'n.m.'爲他們的答覆,並指出我在正確的方向!我會選擇你的答案,但我想顯示這個解決方案,而不寫類模板專業化。

+0

Col ** u ** mbo。中間有一個你。 – Columbo

+1

@Columbo除非他是[斯里蘭卡](https://en.wikipedia.org/wiki/Colombo)粉絲... – Barry

+0

@Barry我很欣賞研究,但我的名字仍然是科倫坡。我不叫你貝瑞,因爲我喜歡瞎鬧。 ;-) – Columbo

7

您使用Base<ProductX<SYNC>, SYNC>作爲s_map定義中的成員專業化,所以您實際上需要Base(§14.5.5.3/ 1)的相應部分專業化。換句話說,你試圖定義一個不存在的部分專業化的成員。

嘗試提供專業化:

template<typename SYNC> 
struct ProductX; 

//-- CRTP base class with some sync/lock mechanism 
template<typename T, typename SYNC> 
struct Base {}; 
template<typename SYNC> 
struct Base<ProductX<SYNC>, SYNC> { 
    static std::unordered_map<int, std::string> s_map; 
    static SYNC s_sync; 
}; 

//-- derived class using CRTP 
template<typename SYNC> 
struct ProductX : public Base<ProductX<SYNC>, SYNC> {}; 

//-- static initialisation 
template<typename SYNC> 
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { 
    { 1, "value_1" }, 
    { 2, "value_2" } 
}; 

Demo

+0

謝謝你的回答科倫坡!你是對的,並指出我正確的方向。但是,對於我而言,編寫模板類專業化並不是很方便,因爲我必須爲每個創建的ProductX重寫所有內容。有關更多詳情,請參閱下面的答案。 –

4

一個簡化的例子。

template <class A, class B> 
struct C 
{ 
    static int x; 
}; 

template <class A, class B> int C<A, B>::x = 0; // this works 

然而

template <class A> int C<A, double>::x = 0; // same error as yours 

後者定義屬於哪個不存在℃的部分特。創建一個:

template <class A> 
struct C<A, double> 
{ 
    static int x; 
}; 

template <class A> int C<A, double>::x = 1; 

一切都很好。

+0

感謝您的回答!作爲科倫坡,你指出了我的正確方向。有關更多詳細信息,請參閱我自己的答案 –