2015-02-15 14 views
7

Tôi đang tạo một số loại container và tôi muốn bắt chước giao diện của một std::vector. Tuy nhiên, tôi đang gặp khó khăn trong việc hiểu cách hoạt động của the constructor overload (4). Vấn đề là nó thường xung đột với tình trạng quá tải (2).std :: vector constructor lấy cặp vòng lặp

// (2) 
vector(size_type count, const T& value, const Allocator& alloc = Allocator()); 
// (4) 
template<class InputIt> 
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator()); 

Theo cppreference, cho đến khi C++ 11:

constructor này có tác dụng tương tự như tình trạng quá tải (2) nếu InputIt là một loại không thể thiếu.

tôi hiểu nó như thế nào đã được thực hiện (tag dispatching hoặc mẫu chuyên môn, tôi giả sử), nhưng tôi không có ý tưởng như thế nào hành vi mới được thực hiện trong C++ 11:

quá tải này chỉ tham gia ở độ phân giải quá tải nếu InputIt thỏa mãn InputIterator, để tránh sự mơ hồ với tình trạng quá tải (2).

Đó có phải là một số loại lừa SFINAE không? Tôi không hiểu làm thế nào SFINAE có thể làm việc ở đây. Và, kể từ khi khái niệm hoặc không phải là một điều trong C + + 11 (cũng không C + + 14), tôi không có ý tưởng về cách tôi có thể làm điều đó cho container của tôi.

Do đó câu hỏi của tôi: làm thế nào nó được thực hiện trong thư viện chuẩn (hoặc ít nhất là một dự đoán), và làm thế nào tôi có thể làm điều đó tương đối dễ dàng cho container của tôi?

+1

Nhận xét khó hiểu: Không có * việc triển khai thư viện chuẩn. Triển khai thực hiện vectơ của libC++ [sử dụng SFINAE qua 'enable_if'] (https://github.com/llvm-mirror/libcxx/blob/master/include/vector#L532). libstdC++ [sử dụng triển khai tương tự] (https://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01523_source.html#l00401), nhưng bỏ qua kiểm tra cấu trúc. – dyp

+0

@dyp Vâng, tôi biết không có triển khai độc đáo, nhưng tôi không biết cách xây dựng nó (đó là lý do tôi thêm vào "hoặc ít nhất là một dự đoán"). Cảm ơn các liên kết, điều đó thật thú vị. – Nelfeal

Trả lời

6

Cách nó hiện được diễn đạt trong tiêu chuẩn khá thú vị. [Sequence.reqmts]/P15:

Mức độ mà một thực hiện xác định rằng một loại không thể một iterator đầu vào là không xác định, ngoại trừ việc tối thiểu không thể thiếu loại sẽ không đủ điều kiện như vòng lặp đầu vào.

Nói cách khác, nó đủ để triển khai chỉ thử nghiệm cho các loại tích phân, nhưng chúng có thể làm được nhiều hơn nếu chúng muốn.

Với SFINAE thân thiện std::iterator_traits (bình chọn vào C++ 17 giấy làm việc như một vấn đề LWG, nhưng có lẽ được cung cấp bởi hầu hết các trường tất cả cùng anyway), ví dụ, người ta có thể kiểm tra rằng std::iterator_traits<InputIterator>::iterator_category là hợp lệ và biểu thị một loại có nguồn gốc từ std::input_iterator_tag với một cái gì đó như

template<class InputIt, std::enable_if_t<std::is_base_of<std::input_iterator_tag, 
          typename std::iterator_traits<InputIterator>::iterator_category>::value, int> = 0> 
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator()); 

Lưu ý rằng đây chỉ là bằng chứng về khái niệm. Việc triển khai thực sự trong các thư viện chuẩn có thể là 1) phức tạp hơn (ví dụ, nó có thể tối ưu hóa dựa trên danh mục vòng lặp - cho trình vòng lặp chuyển tiếp hoặc tốt hơn, nó có thể cấp phát bộ nhớ cho tất cả các phần tử trong một lần) và 2) thậm chí xấu hơn điều này và chứa dấu gạch dưới để tránh xung đột tên.

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