2012-09-14 29 views
25

Hãy xem xét các chức năng:initializer_list và kiểu mẫu trích

template<typename T> 
void printme(T&& t) { 
    for (auto i : t) 
    std::cout << i; 
} 

hay bất kỳ chức năng khác mà hy vọng một tham số với một bắt đầu()/end() - cho phép loại.

Tại sao điều sau đây là bất hợp pháp?

printme({'a', 'b', 'c'});

Khi tất cả đều là chính đáng:

printme(std::vector<char>({'a', 'b', 'c'})); 
printme(std::string("abc")); 
printme(std::array<char, 3> {'a', 'b', 'c'}); 

Chúng tôi thậm chí có thể viết này:

const auto il = {'a', 'b', 'c'}; 
printme(il); 

hoặc

printme<std::initializer_list<char>>({'a', 'b', 'c'}); 

Trả lời

29

Dòng đầu tiên của bạn printme({'a', 'b', 'c'}) là bất hợp pháp vì đối số mẫu T không thể suy ra được. Nếu bạn chỉ định rõ ràng đối số mẫu, nó sẽ hoạt động, ví dụ: printme<vector<char>>({'a', 'b', 'c'}) hoặc printme<initializer_list<char>>({'a', 'b', 'c'}).

Các đối tượng khác bạn liệt kê là hợp pháp vì đối số có loại được xác định rõ, vì vậy đối số mẫu T có thể được suy luận tốt.

Đoạn mã của bạn với auto cũng hoạt động vì il được coi là loại std::initializer_list<char> và do đó đối số mẫu cho printme() có thể được suy luận.


duy nhất "funny" một phần ở đây là auto sẽ chọn loại std::initializer_list<char> nhưng đối số mẫu sẽ không. Điều này là do § 14.8.2.5/5 của tiêu chuẩn C++ 11 tuyên bố rõ ràng rằng đây là ngữ cảnh không được suy luận cho một đối số mẫu:

Tham số chức năng mà đối số liên quan là danh sách khởi tạo (8.5.4) nhưng tham số không có std :: initializer_list hoặc tham chiếu đến có thể cv-đủ điều kiện std :: initializer_list loại.[Ví dụ:

template<class T> void g(T); 
g({1,2,3}); // error: no argument deduced for T 

- end dụ]

Tuy nhiên với auto, § 7.1.6.4/6 đã hỗ trợ rõ ràng cho std::initializer_list<>

nếu initializer là một braced-init-list (8.5.4), với std::initializer_list<U>.

+1

+1 Tôi đã học được điều gì đó. nâng cao 'std :: initialiser_list <>' thành một hàm ngoài một hàm thư viện thông thường. – Walter

+3

Chỉ để hoàn thành. Đây là một cách để giải quyết vấn đề: http://pastebin.com/huEGwnDt – 4ZM

+4

Chúng ta có biết * tại sao * đây là trường hợp? Nó có vẻ khá lạ đối với tôi rằng nếu tôi muốn cho phép một hàm mẫu (có thể là một thuật toán dựa trên phạm vi) để lấy một đối số danh sách khởi tạo, tôi phải cung cấp quá tải cho 'std :: initializer_list'. –

4

này đặc biệt được bảo hiểm theo § 14.8.2.5/5

Một số chức năng mà lập luận liên quan là một danh sách initializer nhưng tham số không có std::initializer_list hoặc tài liệu tham khảo để có thể cv-trình độ std::initializer_list loại. [Ví dụ:

template<class T> void g(T); 
g({1,2,3}); // error: no argument deduced for T 

-end dụ]

Để làm cho nó làm việc, bạn có thể chỉ định kiểu mẫu đối số một cách rõ ràng.

printme<std::initializer_list<int>>({1,2,3,4}); 
6

Bạn cũng có thể quá tải hàm để lấy một đối số kiểu initializer_list một cách rõ ràng.

template<typename T> 
void printme(std::initializer_list<T> t) { 
    for (auto i : t) 
    std::cout << i; 
} 
+0

Chắc chắn, nhưng điều đó sẽ làm cho các phiên bản khác không thành công, ví dụ: 'printme (std :: vector ({'a', 'b', 'c'}));'. Chuyên môn về mẫu sẽ không hoạt động ở đây. – 4ZM

+1

Không, không. Phiên bản khác vẫn hoạt động. http://ideone.com/f2yZ7 –

+0

Ồ, nhưng điều đó thật tuyệt! Cảm ơn bạn. Tôi nghĩ rằng tôi đã thử điều này, nhưng tôi đã sai. Chuyên môn về mẫu hoạt động tốt ở đây. Vì hàm này có thể được thực hiện trong _exactly_ theo cùng một cách, tất cả những gì còn lại là làm thế nào để tìm ra cách làm cho một trong số chúng gọi cho nhau ... – 4ZM

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