Hướng dẫn khấu trừ mẫu là gì và khi nào chúng ta nên sử dụng chúng?


87

Tiêu chuẩn C ++ 17 giới thiệu "hướng dẫn khấu trừ mẫu". Tôi thu thập chúng một cái gì đó để làm với suy luận đối số mẫu mới cho các hàm tạo được giới thiệu trong phiên bản này của tiêu chuẩn, nhưng tôi chưa thấy một giải thích đơn giản, kiểu Câu hỏi thường gặp về chúng là gì và chúng dùng để làm gì.

  • Hướng dẫn khấu trừ mẫu trong C ++ 17 là gì?

  • Tại sao (và khi nào) chúng ta cần chúng?

  • Làm cách nào để khai báo chúng?



Đặc biệt, tôi muốn biết liệu có bất kỳ hướng dẫn khấu trừ nào thực sự được cung cấp bởi C ++ 17 STL (ví dụ: cho std :: cặp hoặc std :: tuple) hay không. Danh sách đầy đủ các kiểu mẫu tiêu chuẩn "có thể suy luận" của C ++ 17 là gì?
Quuxplusone 21/02/17


Tôi muốn biết liệu có trình biên dịch nào hỗ trợ điều này không. Tôi đã thử gcc, clang và vc ++. rextester.com/DHPHC32332 Nevermind, tôi thấy nó chỉ hoạt động với gc ++ 8.1 C ++ 17 và 2a g ++ -std = c ++ 17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Jean-Simon Brochu

Câu trả lời:


98

Hướng dẫn suy diễn mẫu là các mẫu được liên kết với một lớp mẫu cho trình biên dịch biết cách dịch một tập hợp các đối số của phương thức khởi tạo (và các kiểu của chúng) thành các tham số mẫu cho lớp.

Ví dụ đơn giản nhất là của std::vectorvà hàm tạo của nó nhận một cặp trình vòng lặp.

template<typename Iterator>
void func(Iterator first, Iterator last)
{
  vector v(first, last);
}

Trình biên dịch cần phải tìm ra những gì vector<T>'s Tloại sẽ. Chúng tôi biết câu trả lời là gì; Tnên được typename std::iterator_traits<Iterator>::value_type. Nhưng làm thế nào để chúng ta nói với trình biên dịch mà không cần phải gõ vector<typename std::iterator_traits<Iterator>::value_type>?

Bạn sử dụng hướng dẫn khấu trừ:

template<typename Iterator> vector(Iterator b, Iterator e) -> 
    vector<typename std::iterator_traits<Iterator>::value_type>;

Điều này cho trình biên dịch biết rằng, khi bạn gọi một hàm vectortạo phù hợp với mẫu đó, nó sẽ suy ra sự vectorchuyên môn hóa bằng cách sử dụng mã ở bên phải của ->.

Bạn cần hướng dẫn khi loại trừ kiểu khỏi các đối số không dựa trên kiểu của một trong những đối số đó. Khởi tạo a vectortừ một initializer_listcách rõ ràng sử dụng vector's T, vì vậy nó không cần hướng dẫn.

Phía bên trái không nhất thiết phải chỉ định một phương thức khởi tạo thực tế. Cách hoạt động của nó là, nếu bạn sử dụng phép suy diễn hàm tạo mẫu trên một kiểu, nó sẽ khớp với các đối số mà bạn chuyển với tất cả các hướng dẫn suy luận (các hàm tạo thực tế của mẫu chính cung cấp hướng dẫn ngầm). Nếu có một kết quả phù hợp, nó sẽ sử dụng điều đó để xác định đối số mẫu nào cần cung cấp cho loại.

Nhưng một khi việc khấu trừ đó được thực hiện, khi trình biên dịch tìm ra các tham số khuôn mẫu cho kiểu, quá trình khởi tạo cho đối tượng của kiểu đó sẽ tiến hành như thể không có điều gì xảy ra. Nghĩa là, hướng dẫn khấu trừ được chọn không phải khớp với hàm tạo đã chọn.

Điều này cũng có nghĩa là bạn có thể sử dụng các hướng dẫn với tổng hợp và khởi tạo tổng hợp:

template<typename T>
struct Thingy
{
  T t;
};

Thingy(const char *) -> Thingy<std::string>;

Thingy thing{"A String"}; //thing.t is a `std::string`.

Vì vậy, các hướng dẫn khấu trừ chỉ được sử dụng để tìm ra kiểu đang được khởi tạo. Quá trình khởi tạo thực tế hoạt động chính xác như nó đã làm trước đây, khi quyết định đó đã được thực hiện.


7
Hmm, tôi chợt nhận ra rằng ngay cả khi có hướng dẫn, vector v{first, last};sẽ không làm đúng :(
TC

3
@TC… trừ khi điều đúng là tạo một vectơ của các trình vòng lặp. Và std::string{32,'*'}[0] == ' '(đối với ASCII). Nhưng tất cả điều này đã đúng kể từ C ++ 11.
Arne Vogel

2
điều gì xảy ra với tham số vectơ trình cấp phát? điều gì sẽ xảy ra nếu tham số vectơ trình cấp phát không có đối số mặc định? (bạn không thể suy ra nó từ InputIterator)
gnzlbg

@NicolBolas: Bạn có vui lòng giải thích chi tiết về cách các hướng dẫn suy diễn ngầm và rõ ràng có thể hoạt động trong ngữ cảnh của các lớp chuyên biệt một phần hoặc toàn bộ (mà các hàm tạo của chúng rõ ràng không cần phải có các kiểu tham số khớp với các kiểu của mẫu chính) không? Thật khó để tìm thấy thông tin về điều này thông qua một tìm kiếm nhanh.
user541686

1
@NicolBolas: Tôi hiểu rồi. Tôi không rõ rằng câu hỏi là về hướng dẫn khấu trừ rõ ràng ... Tôi nghĩ sẽ hữu ích nếu bạn chỉ đưa những gì bạn đã viết vào bình luận này.
user541686
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.