Question Pourquoi std :: stack n'utilise-t-il pas le paramètre modèle de modèle?


Pourquoi faire std::stack et std::queue utiliser le paramètre type template à la place du paramètre template de modèle pour leur type de conteneur sous-jacent?

c'est-à-dire pourquoi stack déclaré comme ceci:

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

mais pas comme ça:

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

?


35
2017-08-02 13:20


origine


Réponses:


Parce que typiquement les conteneurs aiment std::vector avoir plus d'un argument de modèle. En ne vous souciant pas du fait qu’il s’agit d’un modèle, vous autorisez l’utilisation de tous les types de conteneurs.

Comment serait

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

adapter sur

template<typename> class Container

comme vous l'auriez dans votre stack? (Indice: ce n’est pas le cas!) Vous auriez besoin de cas particuliers pour chaque nombre et type d’arguments de modèle (type vs non-type) que vous souhaitez prendre en charge, ce qui est stupide, plus d'informations qu'un simple

typename Container

Notez que pour obtenir les arguments réels du modèle, par ex. une std::vector, vous avez les typedefs std::vector::value_type et std::vector::allocator_type, ce qui élimine la nécessité d’avoir ces types disponibles explicitement là où vous utilisez réellement le type (c.-à-d. le Container de stack).


38
2017-08-02 13:37



L'utilisation d'un paramètre de modèle de modèle restreindrait les types que vous pourriez utiliser comme conteneur sous-jacent à ceux qui exposent la même signature de modèle. Ce formulaire autorise les types arbitraires tant qu'ils supportent l'interface attendue.


18
2017-08-02 13:37



En bref: Parce que l'utilisation d'un paramètre de modèle de modèle est plus restrictive * que l'utilisation d'un paramètre de type sans offrir aucun avantage.

* Par "restrictif", je veux dire que vous pourriez avoir besoin d'un matériel plus complexe pour obtenir les mêmes résultats qu'avec un paramètre de type "simple".

Pourquoi n'y a-t-il aucun avantage?

Votre std::stack a probablement un attribut comme celui-ci:

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

Si vous remplacez Container, par un paramètre de modèle de modèle, pourquoi voudriez-vous obtenir?

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

Vous instanciez Container seulement une fois et seulement pour T (Container<T>), il y a donc pas d'avantage pour un paramètre de modèle de modèle.

Pourquoi est-ce plus restrictif?

Avec un paramètre modèle de modèle, vous devez passer à std::stack un modèle qui expose la même signature, par exemple:

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

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

Peut-être pourriez-vous utiliser des modèles variadiques:

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>>

Mais que faire si je ne veux pas utiliser la norme 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...

Cela devient un peu compliqué ... Que faire si je veux utiliser mes propres modèles de conteneur qui prennent des paramètres 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...

Mais, si je veux utiliser un conteneur non basé sur un modèle?

struct foo { };
struct foo_container{ };

stack<foo, foo_container> // Error!

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

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

Avec un paramètre de type, il n'y a pas de tels problèmes1:

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

1 Il existe d'autres cas qui ne fonctionnent pas avec un paramètre de modèle de modèle, comme l'utilisation de modèles acceptant un mélange de paramètres de type et de non-type dans des ordres spécifiques, pour lesquels vous pouvez créer des paramètres de modèles génériques, même en utilisant des modèles variadiques.


17
2017-08-02 13:30



Parce qu'il ne compile pas:

std::deque n'est pas de type

template <typename T> class std::deque

c'est de type

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

C’est bien sûr un problème plus général: même si nous devions fournir Alloc paramètre de modèle à notre stack template de classe, la classe ne fonctionnerait désormais qu'avec des conteneurs ayant exactement deux arguments de modèle de type. Ceci est une restriction déraisonnable.


13
2017-08-02 13:37