หากคุณต้องการประเภทของสิ่งที่ไม่ใช่การเรียกใช้ฟังก์ชันstd::result_of
ก็ไม่ต้องใช้ decltype()
สามารถระบุประเภทของนิพจน์ใดก็ได้
หากเรา จำกัด ตัวเองเพียงวิธีต่างๆในการกำหนดประเภทการส่งคืนของการเรียกใช้ฟังก์ชัน (ระหว่างstd::result_of_t<F(Args...)>
และdecltype(std::declval<F>()(std::declval<Args>()...)
) ก็จะมีความแตกต่าง
std::result_of<F(Args...)
ถูกกำหนดให้เป็น:
ถ้านิพจน์
INVOKE (declval<Fn>(), declval<ArgTypes>()...)
ถูกสร้างขึ้นอย่างดีเมื่อถือว่าเป็นตัวถูกดำเนินการที่ไม่ได้ประเมิน (ข้อ 5) ประเภทสมาชิกจะตั้งชื่อประเภทเป็นdecltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
อย่างอื่นจะไม่มีประเภทสมาชิก
ความแตกต่างระหว่างresult_of<F(Args..)>::type
และdecltype(std::declval<F>()(std::declval<Args>()...)
เป็นข้อมูลเกี่ยวกับสิ่งINVOKE
นั้น การใช้declval
/ decltype
โดยตรงนอกจากจะพิมพ์ได้นานขึ้นเล็กน้อยแล้วจะใช้ได้F
ก็ต่อเมื่อสามารถเรียกใช้ได้โดยตรงเท่านั้น (ประเภทอ็อบเจ็กต์ฟังก์ชันหรือฟังก์ชันหรือตัวชี้ฟังก์ชัน) result_of
นอกจากนี้ยังสนับสนุนตัวชี้ไปยังฟังก์ชันสมาชิกและตัวชี้ไปยังข้อมูลสมาชิก
ในขั้นต้นการใช้declval
/ decltype
รับประกันนิพจน์ที่เป็นมิตรกับ SFINAE ในขณะที่std::result_of
อาจทำให้คุณเกิดข้อผิดพลาดอย่างหนักแทนการหักล้มเหลว ที่ได้รับการแก้ไขใน C ++ 14: std::result_of
ตอนนี้จำเป็นต้องเป็นมิตรกับ SFINAE (ขอบคุณเอกสารนี้ )
ดังนั้นในคอมไพเลอร์ C ++ 14 ที่สอดคล้องกันstd::result_of_t<F(Args...)>
นั้นเหนือกว่าอย่างเคร่งครัด มันชัดเจนสั้นและถูกต้อง†สนับสนุนเพิ่มเติมF
s ‡
†เว้นแต่ว่าคุณกำลังใช้มันในบริบทที่คุณไม่ต้องการให้ตัวชี้แก่สมาชิกดังนั้น
std::result_of_t
จะประสบความสำเร็จในกรณีที่คุณอาจต้องการให้มันล้มเหลว
‡มีข้อยกเว้น ในขณะที่มันสนับสนุนตัวชี้ไปยังสมาชิกresult_of
จะไม่ทำงานหากคุณพยายามที่จะยกตัวอย่างที่ไม่ถูกต้องประเภท-ID สิ่งเหล่านี้จะรวมถึงฟังก์ชันที่ส่งคืนฟังก์ชันหรือประเภทนามธรรมตามค่า เช่น:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
การใช้งานที่ถูกต้องจะได้รับแต่นั่นคือรายละเอียดที่คุณไม่ต้องจำไว้ด้วยresult_of_t<F&()>
decltype
decltype
นั้นน่าเกลียดกว่า แต่ก็มีพลังมากกว่าด้วยresult_of
สามารถใช้ได้เฉพาะกับประเภทที่เรียกได้และต้องใช้ประเภทเป็นอาร์กิวเมนต์ ตัวอย่างเช่นคุณไม่สามารถใช้result_of
ที่นี่:template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );
ถ้าอาร์กิวเมนต์สามารถเป็นประเภทเลขคณิตได้ (ไม่มีฟังก์ชันF
ที่คุณสามารถกำหนดF(T,U)
ให้เป็นตัวแทนt+u
ได้สำหรับประเภทที่ผู้ใช้กำหนดคุณสามารถทำได้ในทำนองเดียวกัน (ฉันไม่ได้เล่นด้วยจริงๆ) ฉันคิดว่า การโทรไปยังเมธอดสมาชิกอาจทำได้ยากresult_of
โดยไม่ต้องใช้สารยึดเกาะหรือ