2013-05-16 95 views
30

如何將不同容器聲明模板類(適配器)作爲模板參數? 例如,我需要聲明類:帶模板容器的模板類

template<typename T, typename Container> 
class MyMultibyteString 
{ 
    Container buffer; 
    ... 
}; 

而且我也希望我的基於矢量。如何使它難以定義? (防止有人撰寫此類聲明MyMultibyteString<int, vector<char>>)。

此外,如何實現這樣的結構:

MyMultibyteString<int, std::vector> mbs; 

沒有通過模板參數容器。

回答

59

您應該使用模板模板參數

template<typename T, template <typename, typename> class Container> 
//     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
class MyMultibyteString 
{ 
    Container<T, std::allocator<T>> buffer; 
    // ... 
}; 

這將使你寫:

MyMultibyteString<int, std::vector> mbs; 

這裏是一個編譯live example。寫了上可能是一種替代方法:

template<typename T, 
    template <typename, typename = std::allocator<T>> class Container> 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
class MyMultibyteString 
{ 
    Container<T> buffer; // <== No more need to specify the second argument here 
    // ... 
}; 

這裏是相應live example

唯一需要注意的是模板模板參數聲明中參數的數量和類型必須完全匹配您希望作爲參數傳遞的相應類模板的定義中參數的數量和類型模板參數,而不管這些參數中的某些參數可能具有默認值。

例如,the class template std::vector accepts two template parameters(元素類型和分配器類型),儘管第二個具有默認值std::allocator<T>。正因爲如此,你可以不

template<typename T, template <typename> class Container> 
//        ^^^^^^^^ 
//        Notice: just one template parameter declared! 
class MyMultibyteString 
{ 
    Container<T> buffer; 
    // ... 
}; 

// ... 

MyMultibyteString<int, std::vector> mbs; // ERROR! 
//      ^^^^^^^^^^^ 
//      The std::vector class template accepts *two* 
//      template parameters (even though the second 
//      one has a default argument) 

這意味着你將不能寫一個單獨的類模板,既可以接受std::setstd::vector作爲模板的模板參數,因爲不像std::vectorthe std::set class template accepts three template parameters

+0

真是一個偉大的,完整的答案。 –

+0

@ScottJones:很高興你發現它很有用:) –

+3

@ScottJones關於你的語句:'這意味着你將無法編寫一個可接受std :: set和std :: vector'的類模板:可變模板解決了這個問題? http://stackoverflow.com/a/20499809/2436175 – Antonio

2

另一種方法來解決,這是通過使用可變參數模板,並可以使用任何容器,如上述意見提出,在這裏是實行:

template<template <typename... Args> class Container,typename... Types> 
class Test 
{ 
    public: 
    Container<Types...> test; 

}; 
int main() 
{ 
    Test<std::vector,int> t; 
    Test<std::set,std::string> p; 
    return 0; 
}