2016-08-02 20 views
35

Tại sao phải sử dụng std::stackstd::queue sử dụng thông số mẫu loại thay vì thông số mẫu mẫu cho loại vùng chứa cơ bản của chúng?Tại sao std :: stack không sử dụng tham số mẫu mẫu?

ví dụ: tại sao stack tuyên bố như thế này:

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

nhưng không như thế này:

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

?

+0

@CoryKramer câu hỏi này không trùng lặp với câu hỏi được liên kết: Câu hỏi được liên kết hỏi về nơi chúng tôi cần đặt mẫu/tên tệp, trong khi câu hỏi này là lý do tại sao lớp hiện tại ('deque') có giao diện nhất định, không phải về câu hỏi cú pháp. – bennofs

+1

Các giá trị mặc định có hoạt động ngay cả đối với các tham số mẫu của mẫu không? – anatolyg

+1

@anatolyg Có, chúng hoạt động. –

Trả lời

38

Vì các vùng chứa thông thường như std::vector have more than one template argument. Bằng cách không quan tâm đến nó là một mẫu, bạn cho phép tất cả các loại container được sử dụng.

Làm thế nào sẽ

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

phù hợp vào

template<typename> class Container 

như bạn sẽ có nó trong stack của bạn? (Bạn không cần!) Bạn cần các trường hợp đặc biệt cho mỗi số và loại đối số mẫu (loại so với không phải kiểu) mà bạn muốn hỗ trợ, điều này là ngớ ngẩn, vì những thông thường này không đóng góp bất kỳ nhiều thông tin hơn đơn giản

typename Container 

Lưu ý rằng để lấy các đối số mẫu thực tế của ví dụ a std::vector, bạn có typedefs std::vector::value_typestd::vector::allocator_type, loại bỏ sự cần thiết của việc có các loại này có sẵn một cách rõ ràng nơi bạn thực sự sử dụng loại (ví dụ: Container của stack).

+1

Ouch. Tôi nghĩ nó sẽ thuận tiện hơn để có thể viết 'std :: stack ' mà không chỉ định T hai lần, nhưng không nghĩ về các hạn chế về các tham số mẫu container. – Hedede

+16

@Hedede Nghĩ về các thùng chứa thậm chí không được tạo ra từ các mẫu. Với thiết kế của bạn, bạn không thể làm một cái gì đó như 'std :: stack '. – TartanLlama

+2

Điều này còn tồi tệ hơn "các trường hợp đặc biệt của mỗi _number_ của các mẫu thu thập mẫu", bởi vì tham số mẫu mẫu có thể có sự kết hợp của các đối số mẫu và không kiểu. I E. không chỉ bạn có thể có 'Container ' mà còn 'Container '. Điều đó làm cho nó _exponentially_ tồi tệ hơn. – MSalters

17

Tóm tắt: Do sử dụng thông số mẫu mẫu có hạn chế hơn * sử dụng thông số loại mà không cung cấp bất kỳ lợi thế nào.

* Bằng "hạn chế", tôi có nghĩa là bạn có thể cần một công cụ phức tạp hơn để có được kết quả tương tự với thông số loại "đơn giản".

Tại sao không có lợi thế?

bạn std::stack lẽ đã là một thuộc tính như thế này:

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

Nếu bạn thay thế Container, bởi một mẫu tham số mẫu, tại sao bạn có được?

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

Bạn đang instantiating Container chỉ một lần và chỉ cho T (Container<T>), do đó không có lợi thế cho một tham số mẫu template.

Tại sao nó hạn chế hơn?

Với một tham số template mẫu, bạn phải vượt qua để std::stack một mẫu mà phơi bày cùng một chữ ký, ví dụ:

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

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

Có lẽ bạn có thể sử dụng các mẫu variadic:

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

Nhưng những gì nếu tôi không muốn sử dụng tiêu chuẩn 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... 

Điều này trở nên lộn xộn một chút ... Nếu tôi muốn sử dụng các mẫu chứa của riêng mình có thông số 3/4/N thì sao?

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

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

Nhưng, điều gì sẽ xảy ra nếu tôi muốn sử dụng vùng chứa không có templated?

struct foo { }; 
struct foo_container{ }; 

stack<foo, foo_container> // Error! 

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

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

Với một số loại không có vấn đề như vậy :

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

Có những trường hợp khác mà không làm việc với template mẫu tham số như sử dụng mẫu chấp nhận một kết hợp của nhập và loại thông số không theo thứ tự cụ thể, mà bạn có thể tạo tham số mẫu chung chung, ngay cả khi sử dụng mẫu variadic.

+0

Tôi nghĩ đây không phải là câu trả lời đúng: xem các câu trả lời khác vì một lý do chính xác. –

+0

@KonradRudolph Trong C++ 11, bạn có thể sử dụng 'template class Container' và nó sẽ làm việc với tham số mẫu template. – Holt

+0

@Holt Đúng, đủ công bằng. Điều đó nói rằng, giao diện của khóa học có trước C++ 11, và lý do * cho thiết kế giao diện là đầu tiên và quan trọng nhất là hạn chế kỹ thuật của pre-11 C++. –

13

Because it doesn’t compile:

std::deque không phải là loại

template <typename T> class std::deque 

đó là loại

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

Điều này tất nhiên là một vấn đề tổng quát hơn: ngay cả nếu chúng ta cung cấp Alloc tham số mẫu cho mẫu lớp stack của chúng tôi, lớp giờ đây sẽ chỉ hoạt động với các vùng chứa cũ thực hiện hai đối số mẫu kiểu. Đây là một hạn chế không hợp lý.

+0

@Holt ở đây có một câu trả lời hay về tham số kiểu cho phép sử dụng các gói không chứa mẫu như 'struct foo; struct foo_container; sử dụng foo_stack = std :: stack '. Nhưng khi nói về các tiêu chuẩn hiện đại, sẽ 'template 'cho phép sử dụng các thùng chứa như vậy? tức là, mẫu variadic có thể "giảm" thành một lớp đơn giản không có tham số mẫu không? – Artalus

+0

@Artalus Câu hỏi hay. Không, nó không thể. Câu trả lời của anh ấy là sao lưu, nhân tiện. –

18

Sử dụng thông số mẫu mẫu sẽ giới hạn các loại mà bạn có thể sử dụng làm vùng chứa bên dưới cho các loại hiển thị chữ ký mẫu giống nhau. Biểu mẫu này cho phép các loại tùy ý miễn là chúng hỗ trợ giao diện dự kiến.

Các vấn đề liên quan