คำแนะนำการหักเทมเพลตคือรูปแบบที่เชื่อมโยงกับคลาสเทมเพลตที่บอกคอมไพลเลอร์ว่าจะแปลชุดของอาร์กิวเมนต์ตัวสร้าง (และประเภท) เป็นพารามิเตอร์เทมเพลตสำหรับคลาสได้อย่างไร
ตัวอย่างที่ง่ายที่สุดคือของstd::vector
และตัวสร้างที่รับคู่ตัววนซ้ำ
template<typename Iterator>
void func(Iterator first, Iterator last)
{
vector v(first, last);
}
คอมไพเลอร์ต้องการที่จะคิดออกว่าvector<T>
's T
ประเภทจะได้รับ เรารู้ว่าคำตอบคืออะไร ควรจะเป็นT
typename std::iterator_traits<Iterator>::value_type
แต่เราจะบอกคอมไพเลอร์ได้อย่างไรโดยไม่ต้องพิมพ์vector<typename std::iterator_traits<Iterator>::value_type>
?
คุณใช้คู่มือการหักเงิน:
template<typename Iterator> vector(Iterator b, Iterator e) ->
vector<typename std::iterator_traits<Iterator>::value_type>;
นี้จะบอกคอมไพเลอร์ที่ว่าเมื่อคุณเรียกvector
ที่ตรงกับคอนสตรัคว่ารูปแบบก็จะอนุมานเชี่ยวชาญใช้รหัสที่อยู่ด้านขวาของvector
->
คุณต้องการคำแนะนำเมื่อการหักประเภทออกจากอาร์กิวเมนต์ไม่ได้ขึ้นอยู่กับประเภทของอาร์กิวเมนต์เหล่านั้น เริ่มต้นvector
จากinitializer_list
อย่างชัดเจนใช้vector
's T
ดังนั้นจึงไม่จำเป็นต้องแนะนำ
ด้านซ้ายไม่จำเป็นต้องระบุตัวสร้างจริง วิธีการทำงานคือถ้าคุณใช้การหักตัวสร้างเทมเพลตในประเภทจะตรงกับอาร์กิวเมนต์ที่คุณส่งผ่านกับคำแนะนำการหักทั้งหมด (ตัวสร้างจริงของเทมเพลตหลักจะให้คำแนะนำโดยนัย) หากมีการจับคู่จะใช้สิ่งนั้นเพื่อกำหนดอาร์กิวเมนต์ของเทมเพลตที่จะระบุให้กับประเภท
แต่เมื่อการหักนั้นเสร็จสิ้นเมื่อคอมไพเลอร์หาพารามิเตอร์เทมเพลตสำหรับชนิดแล้วการเริ่มต้นสำหรับออบเจ็กต์ประเภทนั้นจะดำเนินต่อไปราวกับว่าไม่มีสิ่งใดเกิดขึ้น นั่นคือคำแนะนำการหักเงินที่เลือกไม่จำเป็นต้องตรงกับตัวสร้างที่เลือก
นอกจากนี้ยังหมายความว่าคุณสามารถใช้คำแนะนำที่มีการรวมและการเริ่มต้นรวม:
template<typename T>
struct Thingy
{
T t;
};
Thingy(const char *) -> Thingy<std::string>;
Thingy thing{"A String"};
ดังนั้นคำแนะนำการหักจะใช้เพื่อหาประเภทที่กำลังเริ่มต้นเท่านั้น ขั้นตอนการเริ่มต้นจริงจะทำงานเหมือนกับที่เคยทำมาก่อนเมื่อมีการพิจารณาแล้ว