2016-08-02 102 views
35

爲什麼std::stackstd::queue對於其基礎容器類型使用類型模板參數而不是模板模板參數?爲什麼std :: stack不使用模板模板參數?

即爲什麼聲明stack這樣的:

template<typename T, typename Container = deque<T>> 
class stack; 

,但不喜歡這樣的:

template<typename T, template<typename> class Container = deque> 
class stack; 

+0

@CoryKramer這個問題不是鏈接問題的重複:鏈接的問題詢問我們需要將模板/類型名放在哪裏,而這個問題是關於爲什麼現有類('deque')具有特定的接口,而不是關於句法問題。 – bennofs

+1

默認即使對模板模板參數有效嗎? – anatolyg

+1

@anatolyg是的,他們工作。 –

回答

38

因爲通常像容器std::vector have more than one template argument。通過不關心它是一個模板,你可以使用每種容器。

如何將

template<class T, class Allocator = std::allocator<T>> class vector; 

配合到

template<typename> class Container 

,你不應該在你的stack? (提示:它不!)你會需要特殊情況下每個數字和模板參數(類型與非類型),你想支持,這是愚蠢的,因爲這些通常不貢獻任何比簡單更多的信息

typename Container 

請注意,要獲得例如實際的模板參數一個std::vector,您有typedefs std::vector::value_typestd::vector::allocator_type,刪除需要明確地在實際使用類型(即Containerstack)的地方使用這些類型。

+1

哎。我認爲能夠在不指定T兩次的情況下編寫'std :: stack '會更方便,但沒有考慮對容器模板參數的限制。 – Hedede

+16

@Hedede也想一下甚至沒有從模板實例化的容器。通過你的設計,你不能做像'std :: stack '這樣的東西。 – TartanLlama

+2

由於模板模板參數可能混合了類型和非類型模板參數,所以它比「每個模板參數的特殊情況」差得多。即您不僅可以擁有Container ,還可以使用Container 。這使得它顯着惡化。 – MSalters

17

總之:因爲使用模板模板參數比使用類型參數更具限制性而沒有提供任何優勢。由於「限制性」我的意思是你可能需要一個更復雜的東西來獲得相同的結果,以「簡單」的類型參數。

爲什麼沒有優勢?

std::stack可能已經像這樣的屬性:

template <typename T, typename Container> 
struct stack { 
    Container container; 
}; 

如果更換Container,通過模板的模板參數,你爲什麼會獲得?

template <typename T, template <typename...> class Container> 
struct stack { 
    Container<T> container; 
}; 

您要爲TContainer<T>)實例Container只有一次,只有,所以模板的模板參數沒有優勢

爲什麼它更具限制性?

隨着模板的模板參數,你必須傳遞給std::stack一個模板,露出相同的簽名,例如:

template <typename T, template <typename> class Container> 
struct stack; 

stack<int, std::vector> // Error: std::vector takes two template arguments 

也許你可以使用可變參數模板:

template <typename T, template <typename....> class Container> 
struct stack { 
    Container<T> container; 
}; 

stack<int, std::vector> // Ok, will use std::vector<int, std::allocator<int>> 

但什麼如果我不想使用標準std::allocator<int>

template <typename T, 
      template <typename....> class Container = std::vector, 
      typename Allocator = std::allocator<T>> 
struct stack { 
    Container<T, Allocator> container; 
}; 

stack<int, std::vector, MyAllocator> // Ok... 

這變得有點混亂......如果我想使用我自己的容器模板,需要3/4/N參數怎麼辦?

template <typename T, 
      template <typename... > class Container = std::vector, 
      typename ...Args> 
struct stack { 
    Container<T, Args...> container; 
}; 

stack<int, MyTemplate, MyParam1, MyParam2> // Ok... 

但是,如果我想使用非模板容器?

struct foo { }; 
struct foo_container{ }; 

stack<foo, foo_container> // Error! 

template <typename... > 
using foo_container_template = foo_container; 

stack<foo, foo_container_template> // Ok... 

與一類參數不存在這樣的問題:

stack<int> 
stack<int, std::vector<int, MyAllocator<int>> 
stack<int, MyTemplate<int, MyParam1, MyParam2>> 
stack<foo, foo_container> 

還有其他一些情況下不與模板的模板參數工作,如使用模板接受的混合按特定順序輸入類型和非類型參數,爲此您甚至可以使用可變參數模板創建通用模板模板參數。

+0

我不認爲這是完全正確的答案:查看其他答案的正確原因。 –

+0

@KonradRudolph在C++ 11中,你可以使用'template class Container',它可以使用模板模板參數。 – Holt

+0

@霍爾特真的,夠公平的。也就是說,接口當然早於C++ 11,接口設計的*原因首先是Pre-11 C++的技術限制。 –

13

Because it doesn’t compile

std::deque的類型是不

template <typename T> class std::deque 

這類型的

template<class T, class Alloc> class std::deque 

這當然是一個比較普遍的問題:即使我們提供Alloc模板參數傳遞給我們的stack類模板,該類現在只適用於具有ex實際上是兩種類型的模板參數。這是一個不合理的限制。

+0

@Holt在這裏有一個關於type-parameter允許使用非模板容器的好回答,比如'struct foo; struct foo_container;使用foo_stack = std :: stack '。但是在談論現代標準時,'template '是否允許使用這種容器?即,可變參數模板能夠「減少」到沒有模板參數的簡單類嗎? – Artalus

+0

@Artalus好問題。不,它不能。順便提一下,他的回答是支持的。 –

18

使用模板模板參數會將可用作底層容器的類型限制爲暴露相同模板簽名的類型。只要它支持預期的接口,這種形式允許任意類型。