คุณต้องเข้าใจปัญหาการส่งต่อ คุณสามารถอ่านรายละเอียดปัญหาทั้งหมดแต่ฉันจะสรุป
โดยพื้นฐานแล้วเมื่อได้รับนิพจน์E(a, b, ... , c)เราต้องการให้นิพจน์f(a, b, ... , c)นั้นเทียบเท่า ใน C ++ 03 สิ่งนี้เป็นไปไม่ได้ มีหลายครั้ง แต่พวกเขาล้มเหลวในบางเรื่อง
วิธีที่ง่ายที่สุดคือใช้การอ้างอิง lvalue:
template <typename A, typename B, typename C>
void f(A& a, B& b, C& c)
{
    E(a, b, c);
}
แต่สิ่งนี้ล้มเหลวในการจัดการค่าชั่วคราว: f(1, 2, 3);เนื่องจากไม่สามารถผูกกับการอ้างอิง lvalue ได้
ความพยายามครั้งต่อไปอาจเป็น:
template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c)
{
    E(a, b, c);
}
ซึ่งแก้ไขปัญหาข้างต้น แต่พลิก flops ตอนนี้ไม่อนุญาตให้Eมีอาร์กิวเมนต์ที่ไม่ใช่ const:
int i = 1, j = 2, k = 3;
void E(int&, int&, int&); f(i, j, k); // oops! E cannot modify these
ความพยายามที่สามยอมรับ const อ้างอิง แต่แล้วconst_cast's constห่าง:
template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c)
{
    E(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c));
}
สิ่งนี้ยอมรับค่าทั้งหมดสามารถส่งผ่านค่าทั้งหมด แต่อาจนำไปสู่พฤติกรรมที่ไม่ได้กำหนด:
const int i = 1, j = 2, k = 3;
E(int&, int&, int&); f(i, j, k); // ouch! E can modify a const object!
ทางออกสุดท้ายจะจัดการทุกสิ่งอย่างถูกต้อง ... ด้วยราคาที่ไม่สามารถรักษาได้ คุณให้การโอเวอร์โหลดของfพร้อมชุดค่าผสมทั้งหมดและไม่ใช่ค่าคงที่:
template <typename A, typename B, typename C>
void f(A& a, B& b, C& c);
template <typename A, typename B, typename C>
void f(const A& a, B& b, C& c);
template <typename A, typename B, typename C>
void f(A& a, const B& b, C& c);
template <typename A, typename B, typename C>
void f(A& a, B& b, const C& c);
template <typename A, typename B, typename C>
void f(const A& a, const B& b, C& c);
template <typename A, typename B, typename C>
void f(const A& a, B& b, const C& c);
template <typename A, typename B, typename C>
void f(A& a, const B& b, const C& c);
template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c);
ไม่มีข้อโต้แย้งต้องมี 2 ชุดNเป็นฝันร้าย เราต้องการทำสิ่งนี้โดยอัตโนมัติ
(นี่คือสิ่งที่เราจะได้รับคอมไพเลอร์อย่างมีประสิทธิภาพสำหรับเราใน C ++ 11)
ใน C ++ 11 เราได้รับโอกาสแก้ไข วิธีการหนึ่งแก้ไขกฎการหักเงินของเทมเพลตสำหรับประเภทที่มีอยู่ แต่สิ่งนี้อาจทำลายรหัสได้มาก ดังนั้นเราต้องหาวิธีอื่น
การแก้ปัญหาคือแทนที่จะใช้ที่เพิ่มใหม่rvalue อ้างอิง ; เราสามารถนำกฎใหม่มาใช้เมื่อลดประเภทการอ้างอิงค่า rvalue และสร้างผลลัพธ์ที่ต้องการ ท้ายที่สุดเราไม่สามารถทำลายรหัสได้ในขณะนี้
หากได้รับการอ้างอิงถึงการอ้างอิง (การอ้างอิงโน้ตเป็นคำที่ครอบคลุมทั้งความหมายT&และT&&) เราจะใช้กฎต่อไปนี้เพื่อค้นหาประเภทผลลัพธ์:
  "[รับ] ประเภท TR ที่อ้างอิงถึงประเภท T ความพยายามในการสร้างประเภท“ อ้างอิง lvalue กับ cv TR” สร้างประเภท“ อ้างอิง lvalue กับ T” ในขณะที่ความพยายามในการสร้างประเภท“ อ้างอิง rvalue เพื่อ cv TR” สร้างประเภท TR "
หรือในรูปแบบตาราง:
TR   R
T&   &  -> T&  // lvalue reference to cv TR -> lvalue reference to T
T&   && -> T&  // rvalue reference to cv TR -> TR (lvalue reference to T)
T&&  &  -> T&  // lvalue reference to cv TR -> lvalue reference to T
T&&  && -> T&& // rvalue reference to cv TR -> TR (rvalue reference to T)
ถัดไปด้วยการหักล้างอาร์กิวเมนต์เทมเพลต: หากอาร์กิวเมนต์เป็น lvalue A เราจะจัดหาอาร์กิวเมนต์เท็มเพลตที่มีการอ้างอิง lvalue ไปยัง A มิฉะนั้นเราจะอนุมานตามปกติ สิ่งนี้ให้การอ้างอิงสากลที่เรียกว่า( การอ้างอิงการส่งต่อคำว่าขณะนี้เป็นทางการ)
ทำไมถึงมีประโยชน์ เนื่องจากการรวมกันเรารักษาความสามารถในการติดตามหมวดหมู่ค่าของประเภท: ถ้ามันเป็น lvalue เรามีพารามิเตอร์ lvalue-reference มิฉะนั้นเราจะมีพารามิเตอร์ rvalue-reference
ในรหัส:
template <typename T>
void deduce(T&& x); 
int i;
deduce(i); // deduce<int&>(int& &&) -> deduce<int&>(int&)
deduce(1); // deduce<int>(int&&)
สิ่งสุดท้ายคือ "ส่งต่อ" หมวดหมู่ค่าของตัวแปร โปรดจำไว้ว่าเมื่อมีการใช้งานฟังก์ชั่นแล้วพารามิเตอร์สามารถส่งผ่านเป็น lvalue ไปยังสิ่งใดก็ได้:
void foo(int&);
template <typename T>
void deduce(T&& x)
{
    foo(x); // fine, foo can refer to x
}
deduce(1); // okay, foo operates on x which has a value of 1
นั่นไม่ดีเลย E ต้องได้รับหมวดหมู่มูลค่าแบบเดียวกันกับที่เราได้รับ! ทางออกคือ:
static_cast<T&&>(x);
สิ่งนี้ทำอะไร พิจารณาว่าเราอยู่ในdeduceฟังก์ชั่นและเราได้ผ่าน lvalue วิธีนี้Tเป็นA&และอื่น ๆ ประเภทเป้าหมายสำหรับหล่อคงเป็นหรือเพียงแค่A& && A&เนื่องจากxเป็นแล้วA&เราจึงไม่ทำอะไรเลยและมีการอ้างอิง lvalue อยู่
เมื่อเราได้รับการผ่านการ rvalue, Tเป็นดังนั้นประเภทเป้าหมายสำหรับการหล่อแบบคงที่คือA A&&ผลการโยนในการแสดงออก rvalue, ซึ่งไม่สามารถส่งผ่านไปยังอ้างอิง lvalue เราได้รักษาหมวดหมู่ค่าของพารามิเตอร์ไว้
การรวมสิ่งเหล่านี้เข้าด้วยกันทำให้เรา "การส่งต่อที่สมบูรณ์แบบ": 
template <typename A>
void f(A&& a)
{
    E(static_cast<A&&>(a)); 
}
เมื่อfได้รับ lvalue ให้Eรับ lvalue เมื่อfรับค่า rvalue Eจะได้ค่า rvalue สมบูรณ์
และแน่นอนเราต้องการกำจัดความน่าเกลียด static_cast<T&&>เป็นความลับและแปลกที่จะจำ; ลองสร้างฟังก์ชั่นยูทิลิตี้ที่เรียกว่าforwardซึ่งทำสิ่งเดียวกัน:
std::forward<A>(a);
// is the same as
static_cast<A&&>(a);
               
              
fเป็นหน้าที่และไม่ใช่การแสดงออกใช่มั้ย